From 19f9147e1076d83dd1111609ca93a01085dbfb4f Mon Sep 17 00:00:00 2001 From: Antonin Descampe Date: Sun, 20 Mar 2011 22:45:24 +0000 Subject: [PATCH] Removed the libs directory containing win32 compiled versions of libpng, libtiff and liblcms. Added a thirdparty directory to include main source files of libtiff, libpng, libz and liblcms to enable support of these formats in the codec executables. CMake will try to statically build these libraries if they are not found on the system. Note that these third party libraries are not required to build libopenjpeg (which has no dependencies). --- CHANGES | 4 + CMakeLists.txt | 233 +- codec/CMakeLists.txt | 21 +- codec/convert.c | 11 +- jpwl/CMakeLists.txt | 38 +- libs/lcms2/lcms2_static.lib | Bin 1312736 -> 0 bytes libs/libtiff/libtiff.lib | Bin 543310 -> 0 bytes libs/libtiff/tiffio.h | 550 -- libs/png/libpng14.lib | Bin 800554 -> 0 bytes libs/png/zlib.lib | Bin 240696 -> 0 bytes mj2/CMakeLists.txt | 18 +- thirdparty/CMakeLists.txt | 20 + {libs/png => thirdparty/include}/zconf.h | 760 +-- thirdparty/include/zconf.h.cmake.msvc | 430 ++ {libs/png => thirdparty/include}/zlib.h | 2970 +++++----- thirdparty/liblcms2/CMakeLists.txt | 20 + thirdparty/liblcms2/COPYING | 8 + .../liblcms2/include}/lcms2.h | 33 +- .../liblcms2/include}/lcms2_plugin.h | 4 +- thirdparty/liblcms2/src/cmscam02.c | 483 ++ thirdparty/liblcms2/src/cmscgats.c | 2655 +++++++++ thirdparty/liblcms2/src/cmscnvrt.c | 1039 ++++ thirdparty/liblcms2/src/cmserr.c | 428 ++ thirdparty/liblcms2/src/cmsgamma.c | 1138 ++++ thirdparty/liblcms2/src/cmsgmt.c | 591 ++ thirdparty/liblcms2/src/cmsintrp.c | 1463 +++++ thirdparty/liblcms2/src/cmsio0.c | 1720 ++++++ thirdparty/liblcms2/src/cmsio1.c | 760 +++ thirdparty/liblcms2/src/cmslut.c | 1665 ++++++ thirdparty/liblcms2/src/cmsmd5.c | 317 ++ thirdparty/liblcms2/src/cmsmtrx.c | 176 + thirdparty/liblcms2/src/cmsnamed.c | 750 +++ thirdparty/liblcms2/src/cmsopt.c | 1631 ++++++ thirdparty/liblcms2/src/cmspack.c | 2558 +++++++++ thirdparty/liblcms2/src/cmspcs.c | 926 +++ thirdparty/liblcms2/src/cmsplugin.c | 612 ++ thirdparty/liblcms2/src/cmsps2.c | 1595 ++++++ thirdparty/liblcms2/src/cmssamp.c | 266 + thirdparty/liblcms2/src/cmssm.c | 734 +++ thirdparty/liblcms2/src/cmstypes.c | 4955 +++++++++++++++++ thirdparty/liblcms2/src/cmsvirt.c | 1148 ++++ thirdparty/liblcms2/src/cmswtpnt.c | 351 ++ thirdparty/liblcms2/src/cmsxform.c | 809 +++ thirdparty/liblcms2/src/lcms2.def | 300 + thirdparty/liblcms2/src/lcms2_internal.h | 652 +++ thirdparty/libpng/CMakeLists.txt | 29 + thirdparty/libpng/LICENSE | 111 + thirdparty/libpng/example.c | 838 +++ thirdparty/libpng/png.c | 918 +++ {libs/png => thirdparty/libpng}/png.h | 0 {libs/png => thirdparty/libpng}/pngconf.h | 0 thirdparty/libpng/pngerror.c | 402 ++ thirdparty/libpng/pngget.c | 925 +++ thirdparty/libpng/pngmem.c | 611 ++ thirdparty/libpng/pngpread.c | 1765 ++++++ thirdparty/libpng/pngpriv.h | 954 ++++ thirdparty/libpng/pngread.c | 1361 +++++ thirdparty/libpng/pngrio.c | 163 + thirdparty/libpng/pngrtran.c | 4203 ++++++++++++++ thirdparty/libpng/pngrutil.c | 3379 +++++++++++ thirdparty/libpng/pngset.c | 1167 ++++ thirdparty/libpng/pngtest.c | 1632 ++++++ thirdparty/libpng/pngtrans.c | 677 +++ thirdparty/libpng/pngwio.c | 241 + thirdparty/libpng/pngwrite.c | 1457 +++++ thirdparty/libpng/pngwtran.c | 566 ++ thirdparty/libpng/pngwutil.c | 2786 +++++++++ thirdparty/libtiff/CMakeLists.txt | 79 + thirdparty/libtiff/t4.h | 292 + thirdparty/libtiff/tif_apple.c | 281 + thirdparty/libtiff/tif_aux.c | 290 + thirdparty/libtiff/tif_close.c | 126 + thirdparty/libtiff/tif_codec.c | 160 + thirdparty/libtiff/tif_color.c | 282 + thirdparty/libtiff/tif_compress.c | 295 + thirdparty/libtiff/tif_config.h | 70 + thirdparty/libtiff/tif_dir.c | 1389 +++++ thirdparty/libtiff/tif_dir.h | 211 + thirdparty/libtiff/tif_dirinfo.c | 904 +++ thirdparty/libtiff/tif_dirread.c | 2081 +++++++ thirdparty/libtiff/tif_dirwrite.c | 1414 +++++ thirdparty/libtiff/tif_dumpmode.c | 126 + thirdparty/libtiff/tif_error.c | 80 + thirdparty/libtiff/tif_extension.c | 118 + thirdparty/libtiff/tif_fax3.c | 1626 ++++++ thirdparty/libtiff/tif_fax3.h | 532 ++ thirdparty/libtiff/tif_fax3sm.c | 1260 +++++ thirdparty/libtiff/tif_flush.c | 74 + thirdparty/libtiff/tif_getimage.c | 2676 +++++++++ thirdparty/libtiff/tif_jbig.c | 385 ++ thirdparty/libtiff/tif_jpeg.c | 2065 +++++++ thirdparty/libtiff/tif_luv.c | 1629 ++++++ thirdparty/libtiff/tif_lzw.c | 1129 ++++ thirdparty/libtiff/tif_next.c | 154 + thirdparty/libtiff/tif_ojpeg.c | 2438 ++++++++ thirdparty/libtiff/tif_open.c | 695 +++ thirdparty/libtiff/tif_packbits.c | 300 + thirdparty/libtiff/tif_pixarlog.c | 1371 +++++ thirdparty/libtiff/tif_predict.c | 736 +++ thirdparty/libtiff/tif_predict.h | 77 + thirdparty/libtiff/tif_print.c | 646 +++ thirdparty/libtiff/tif_read.c | 750 +++ thirdparty/libtiff/tif_stream.cxx | 295 + thirdparty/libtiff/tif_strip.c | 370 ++ thirdparty/libtiff/tif_swab.c | 242 + thirdparty/libtiff/tif_thunder.c | 165 + thirdparty/libtiff/tif_tile.c | 280 + thirdparty/libtiff/tif_unix.c | 296 + thirdparty/libtiff/tif_version.c | 40 + thirdparty/libtiff/tif_warning.c | 81 + thirdparty/libtiff/tif_win32.c | 408 ++ thirdparty/libtiff/tif_write.c | 718 +++ thirdparty/libtiff/tif_zip.c | 419 ++ {libs => thirdparty}/libtiff/tiff.h | 151 +- {libs => thirdparty}/libtiff/tiffconf.h | 78 +- thirdparty/libtiff/tiffio.h | 526 ++ {libs => thirdparty}/libtiff/tiffio.hxx | 6 +- thirdparty/libtiff/tiffiop.h | 350 ++ {libs => thirdparty}/libtiff/tiffvers.h | 4 +- thirdparty/libtiff/uvcode.h | 180 + thirdparty/libz/CMakeLists.txt | 102 + thirdparty/libz/adler32.c | 169 + thirdparty/libz/compress.c | 80 + thirdparty/libz/crc32.c | 442 ++ thirdparty/libz/crc32.h | 441 ++ thirdparty/libz/deflate.c | 1834 ++++++ thirdparty/libz/deflate.h | 342 ++ thirdparty/libz/example.c | 565 ++ thirdparty/libz/gzclose.c | 25 + thirdparty/libz/gzguts.h | 132 + thirdparty/libz/gzlib.c | 537 ++ thirdparty/libz/gzread.c | 653 +++ thirdparty/libz/gzwrite.c | 531 ++ thirdparty/libz/infback.c | 632 +++ thirdparty/libz/inffast.c | 340 ++ thirdparty/libz/inffast.h | 11 + thirdparty/libz/inffixed.h | 94 + thirdparty/libz/inflate.c | 1480 +++++ thirdparty/libz/inflate.h | 122 + thirdparty/libz/inftrees.c | 330 ++ thirdparty/libz/inftrees.h | 62 + thirdparty/libz/minigzip.c | 440 ++ thirdparty/libz/trees.c | 1244 +++++ thirdparty/libz/trees.h | 128 + thirdparty/libz/uncompr.c | 59 + thirdparty/libz/zlib.h | 1613 ++++++ thirdparty/libz/zutil.c | 318 ++ thirdparty/libz/zutil.h | 274 + 148 files changed, 100866 insertions(+), 2511 deletions(-) delete mode 100755 libs/lcms2/lcms2_static.lib delete mode 100644 libs/libtiff/libtiff.lib delete mode 100644 libs/libtiff/tiffio.h delete mode 100755 libs/png/libpng14.lib delete mode 100755 libs/png/zlib.lib create mode 100644 thirdparty/CMakeLists.txt rename {libs/png => thirdparty/include}/zconf.h (65%) mode change 100755 => 100644 create mode 100644 thirdparty/include/zconf.h.cmake.msvc rename {libs/png => thirdparty/include}/zlib.h (50%) mode change 100755 => 100644 create mode 100644 thirdparty/liblcms2/CMakeLists.txt create mode 100644 thirdparty/liblcms2/COPYING rename {libs/lcms2 => thirdparty/liblcms2/include}/lcms2.h (98%) mode change 100755 => 100644 rename {libs/lcms2 => thirdparty/liblcms2/include}/lcms2_plugin.h (99%) mode change 100755 => 100644 create mode 100644 thirdparty/liblcms2/src/cmscam02.c create mode 100644 thirdparty/liblcms2/src/cmscgats.c create mode 100644 thirdparty/liblcms2/src/cmscnvrt.c create mode 100644 thirdparty/liblcms2/src/cmserr.c create mode 100644 thirdparty/liblcms2/src/cmsgamma.c create mode 100644 thirdparty/liblcms2/src/cmsgmt.c create mode 100644 thirdparty/liblcms2/src/cmsintrp.c create mode 100644 thirdparty/liblcms2/src/cmsio0.c create mode 100644 thirdparty/liblcms2/src/cmsio1.c create mode 100644 thirdparty/liblcms2/src/cmslut.c create mode 100644 thirdparty/liblcms2/src/cmsmd5.c create mode 100644 thirdparty/liblcms2/src/cmsmtrx.c create mode 100644 thirdparty/liblcms2/src/cmsnamed.c create mode 100644 thirdparty/liblcms2/src/cmsopt.c create mode 100644 thirdparty/liblcms2/src/cmspack.c create mode 100644 thirdparty/liblcms2/src/cmspcs.c create mode 100644 thirdparty/liblcms2/src/cmsplugin.c create mode 100644 thirdparty/liblcms2/src/cmsps2.c create mode 100644 thirdparty/liblcms2/src/cmssamp.c create mode 100644 thirdparty/liblcms2/src/cmssm.c create mode 100644 thirdparty/liblcms2/src/cmstypes.c create mode 100644 thirdparty/liblcms2/src/cmsvirt.c create mode 100644 thirdparty/liblcms2/src/cmswtpnt.c create mode 100644 thirdparty/liblcms2/src/cmsxform.c create mode 100644 thirdparty/liblcms2/src/lcms2.def create mode 100644 thirdparty/liblcms2/src/lcms2_internal.h create mode 100644 thirdparty/libpng/CMakeLists.txt create mode 100644 thirdparty/libpng/LICENSE create mode 100644 thirdparty/libpng/example.c create mode 100644 thirdparty/libpng/png.c rename {libs/png => thirdparty/libpng}/png.h (100%) mode change 100755 => 100644 rename {libs/png => thirdparty/libpng}/pngconf.h (100%) mode change 100755 => 100644 create mode 100644 thirdparty/libpng/pngerror.c create mode 100644 thirdparty/libpng/pngget.c create mode 100644 thirdparty/libpng/pngmem.c create mode 100644 thirdparty/libpng/pngpread.c create mode 100644 thirdparty/libpng/pngpriv.h create mode 100644 thirdparty/libpng/pngread.c create mode 100644 thirdparty/libpng/pngrio.c create mode 100644 thirdparty/libpng/pngrtran.c create mode 100644 thirdparty/libpng/pngrutil.c create mode 100644 thirdparty/libpng/pngset.c create mode 100644 thirdparty/libpng/pngtest.c create mode 100644 thirdparty/libpng/pngtrans.c create mode 100644 thirdparty/libpng/pngwio.c create mode 100644 thirdparty/libpng/pngwrite.c create mode 100644 thirdparty/libpng/pngwtran.c create mode 100644 thirdparty/libpng/pngwutil.c create mode 100644 thirdparty/libtiff/CMakeLists.txt create mode 100644 thirdparty/libtiff/t4.h create mode 100644 thirdparty/libtiff/tif_apple.c create mode 100644 thirdparty/libtiff/tif_aux.c create mode 100644 thirdparty/libtiff/tif_close.c create mode 100644 thirdparty/libtiff/tif_codec.c create mode 100644 thirdparty/libtiff/tif_color.c create mode 100644 thirdparty/libtiff/tif_compress.c create mode 100644 thirdparty/libtiff/tif_config.h create mode 100644 thirdparty/libtiff/tif_dir.c create mode 100644 thirdparty/libtiff/tif_dir.h create mode 100644 thirdparty/libtiff/tif_dirinfo.c create mode 100644 thirdparty/libtiff/tif_dirread.c create mode 100644 thirdparty/libtiff/tif_dirwrite.c create mode 100644 thirdparty/libtiff/tif_dumpmode.c create mode 100644 thirdparty/libtiff/tif_error.c create mode 100644 thirdparty/libtiff/tif_extension.c create mode 100644 thirdparty/libtiff/tif_fax3.c create mode 100644 thirdparty/libtiff/tif_fax3.h create mode 100644 thirdparty/libtiff/tif_fax3sm.c create mode 100644 thirdparty/libtiff/tif_flush.c create mode 100644 thirdparty/libtiff/tif_getimage.c create mode 100644 thirdparty/libtiff/tif_jbig.c create mode 100644 thirdparty/libtiff/tif_jpeg.c create mode 100644 thirdparty/libtiff/tif_luv.c create mode 100644 thirdparty/libtiff/tif_lzw.c create mode 100644 thirdparty/libtiff/tif_next.c create mode 100644 thirdparty/libtiff/tif_ojpeg.c create mode 100644 thirdparty/libtiff/tif_open.c create mode 100644 thirdparty/libtiff/tif_packbits.c create mode 100644 thirdparty/libtiff/tif_pixarlog.c create mode 100644 thirdparty/libtiff/tif_predict.c create mode 100644 thirdparty/libtiff/tif_predict.h create mode 100644 thirdparty/libtiff/tif_print.c create mode 100644 thirdparty/libtiff/tif_read.c create mode 100644 thirdparty/libtiff/tif_stream.cxx create mode 100644 thirdparty/libtiff/tif_strip.c create mode 100644 thirdparty/libtiff/tif_swab.c create mode 100644 thirdparty/libtiff/tif_thunder.c create mode 100644 thirdparty/libtiff/tif_tile.c create mode 100644 thirdparty/libtiff/tif_unix.c create mode 100644 thirdparty/libtiff/tif_version.c create mode 100644 thirdparty/libtiff/tif_warning.c create mode 100644 thirdparty/libtiff/tif_win32.c create mode 100644 thirdparty/libtiff/tif_write.c create mode 100644 thirdparty/libtiff/tif_zip.c rename {libs => thirdparty}/libtiff/tiff.h (91%) rename {libs => thirdparty}/libtiff/tiffconf.h (75%) create mode 100644 thirdparty/libtiff/tiffio.h rename {libs => thirdparty}/libtiff/tiffio.hxx (89%) mode change 100755 => 100644 create mode 100644 thirdparty/libtiff/tiffiop.h rename {libs => thirdparty}/libtiff/tiffvers.h (57%) create mode 100644 thirdparty/libtiff/uvcode.h create mode 100644 thirdparty/libz/CMakeLists.txt create mode 100644 thirdparty/libz/adler32.c create mode 100644 thirdparty/libz/compress.c create mode 100644 thirdparty/libz/crc32.c create mode 100644 thirdparty/libz/crc32.h create mode 100644 thirdparty/libz/deflate.c create mode 100644 thirdparty/libz/deflate.h create mode 100644 thirdparty/libz/example.c create mode 100644 thirdparty/libz/gzclose.c create mode 100644 thirdparty/libz/gzguts.h create mode 100644 thirdparty/libz/gzlib.c create mode 100644 thirdparty/libz/gzread.c create mode 100644 thirdparty/libz/gzwrite.c create mode 100644 thirdparty/libz/infback.c create mode 100644 thirdparty/libz/inffast.c create mode 100644 thirdparty/libz/inffast.h create mode 100644 thirdparty/libz/inffixed.h create mode 100644 thirdparty/libz/inflate.c create mode 100644 thirdparty/libz/inflate.h create mode 100644 thirdparty/libz/inftrees.c create mode 100644 thirdparty/libz/inftrees.h create mode 100644 thirdparty/libz/minigzip.c create mode 100644 thirdparty/libz/trees.c create mode 100644 thirdparty/libz/trees.h create mode 100644 thirdparty/libz/uncompr.c create mode 100644 thirdparty/libz/zlib.h create mode 100644 thirdparty/libz/zutil.c create mode 100644 thirdparty/libz/zutil.h diff --git a/CHANGES b/CHANGES index 4acd139a..a5f5929f 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,10 @@ What's New for OpenJPEG ! : changed + : added +March 20, 2011 ++ [antonin] added a 'thirdparty' directory to include main source files of libtiff, libpng, libz and liblcms to enable support of these formats in the codec executables. CMake will try to statically build these libraries if they are not found on the system. Note that these third party libraries are not required to build libopenjpeg (which has no dependencies). +- [antonin] removed the 'libs' directory containing win32 compiled versions of libpng, libtiff and liblcms. + March 10, 2011 * [antonin] fixed lt_version in configure.ac diff --git a/CMakeLists.txt b/CMakeLists.txt index c2e5a9a3..f471cb48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,44 +156,26 @@ SUBDIRS(libopenjpeg) #----------------------------------------------------------------------------- # Build CODEC executables ? OPTION(BUILD_CODEC "Build the CODEC executables" ON) -IF(BUILD_CODEC) - SUBDIRS(codec) -ENDIF(BUILD_CODEC) #----------------------------------------------------------------------------- # Build MJ2 executables ? OPTION(BUILD_MJ2 "Build the MJ2 executables." OFF) -IF(BUILD_MJ2) - SUBDIRS(mj2) -ENDIF(BUILD_MJ2) #----------------------------------------------------------------------------- # Build JPWL executables ? OPTION(BUILD_JPWL "Build the JPWL executables" OFF) -IF(BUILD_JPWL) - SUBDIRS(jpwl) -ENDIF(BUILD_JPWL) #----------------------------------------------------------------------------- # Build JP3D executables ? OPTION(BUILD_JP3D "Build the JP3D executables" OFF) -IF(BUILD_JP3D) - SUBDIRS(jp3d) -ENDIF(BUILD_JP3D) #----------------------------------------------------------------------------- # Build INDEXER_JPIP executables ? OPTION(BUILD_INDEXER_JPIP "Build the INDEXER_JPIP executables" OFF) -IF(BUILD_INDEXER_JPIP) - SUBDIRS(indexer_JPIP) -ENDIF(BUILD_INDEXER_JPIP) #----------------------------------------------------------------------------- # Build DOCUMENTATION ? OPTION(BUILD_DOC "Build the doxygen documentation" OFF) -IF(BUILD_DOC) - SUBDIRS(doc) -ENDIF(BUILD_DOC) #----------------------------------------------------------------------------- # For openjpeg team if they ever want CDash+CMake @@ -238,24 +220,6 @@ INSTALL( LICENSE DESTINATION ${OPENJPEG_INSTALL_DOC_DIR}) # -IF(UNIX OR CYGWIN) - SET(CMAKE_INCLUDE_PATH /usr/include /usr/local/include /opt/include - /opt/local/include /usr/include/libpng /usr/include/libpng14 - /usr/include/libpng12 /usr/local/include/libpng - /usr/local/include/libpng14 /usr/local/include/libpng12 - /opt/include/libpng /opt/include/libpng14 /opt/include/libpng12 - /opt/local/include/libpng /opt/local/include/libpng14 - /opt/local/include/libpng12 ) - SET(CMAKE_LIBRARY_PATH /usr/lib /usr/local/lib /opt/lib /opt/local/lib) -ELSEIF(WIN32) - SET(CMAKE_INCLUDE_PATH ${OPENJPEG_SOURCE_DIR}/libs/libtiff - ${OPENJPEG_SOURCE_DIR}/libs/png ${OPENJPEG_SOURCE_DIR}/libs/lcms2 - C:/WINDOWS/system32/user ) - SET(CMAKE_LIBRARY_PATH ${OPENJPEG_SOURCE_DIR}/libs/libtiff - ${OPENJPEG_SOURCE_DIR}/libs/png ${OPENJPEG_SOURCE_DIR}/libs/lcms2 - C:/WINDOWS/system32/user ) -ENDIF() -# FIND_FILE(HAVE_STRINGS_H_FOUND strings.h) IF(NOT HAVE_STRINGS_H_FOUND STREQUAL "HAVE_STRINGS_H_FOUND-NOTFOUND") FIND_FILE(HAVE_STRINGS_H strings.h) @@ -302,71 +266,158 @@ IF(NOT HAVE_UNISTD_H_FOUND STREQUAL "HAVE_UNISTD_H_FOUND-NOTFOUND") SET(HAS_UNISTD_H 1) ENDIF() # -# Does the system have png library installed ? +IF(BUILD_CODEC OR BUILD_JPWL OR BUILD_MJ2) # -FIND_PACKAGE(PNG) # -IF(PNG_FOUND) - SET(HAVE_PNG_H 1) - SET(HAVE_LIBPNG 1) +IF(UNIX OR CYGWIN) + SET(CMAKE_INCLUDE_PATH /usr/include /usr/local/include /opt/include + /opt/local/include /usr/include/libpng /usr/include/libpng14 + /usr/include/libpng12 /usr/local/include/libpng + /usr/local/include/libpng14 /usr/local/include/libpng12 + /opt/include/libpng /opt/include/libpng14 /opt/include/libpng12 + /opt/local/include/libpng /opt/local/include/libpng14) + SET(CMAKE_LIBRARY_PATH /usr/lib /usr/local/lib /opt/lib /opt/local/lib) ENDIF() # -# Does the system have tiff library installed ? -# -FIND_PACKAGE(TIFF) + FIND_PACKAGE(ZLIB QUIET) # -IF(TIFF_FOUND) - SET(HAVE_TIFF_H 1) - SET(HAVE_LIBTIFF 1) -ENDIF() + IF(ZLIB_LIBRARY STREQUAL "ZLIB_LIBRARY-NOTFOUND") + SET(ZLIB_FOUND 0) + ENDIF(ZLIB_LIBRARY STREQUAL "ZLIB_LIBRARY-NOTFOUND") # + IF(ZLIB_FOUND) + SET(HAVE_ZLIB_H 1) + SET(HABE_LIBZ 1) + SET(Z_LIBNAME ${ZLIB_LIBRARIES}) + SET(Z_INCLUDE_DIRNAME ${ZLIB_INCLUDE_DIR}) + ENDIF(ZLIB_FOUND) # -# Does the system have lcms library installed ? + FIND_PACKAGE(PNG QUIET) # -SET(LCMS_LIB "") -FIND_FILE(LCMS2_HEADER_FOUND lcms2.h) + IF(PNG_LIBRARY STREQUAL "PNG_LIBRARY-NOTFOUND") + SET(PNG_FOUND 0) + ENDIF(PNG_LIBRARY STREQUAL "PNG_LIBRARY-NOTFOUND") # -IF(LCMS2_HEADER_FOUND STREQUAL "LCMS2_HEADER_FOUND-NOTFOUND") - SET(LCMS2_HEADER_FOUND "") -ENDIF() -IF(LCMS2_HEADER_FOUND) - FIND_PATH(LCMS_INCLUDE_DIR lcms2.h) - IF(UNIX OR CYGWIN) - FIND_LIBRARY(HAVE_LIBLCMS2 lcms2) - ELSE() - FIND_LIBRARY(HAVE_LIBLCMS2 lcms2_static.lib) - ENDIF() - IF(HAVE_LIBLCMS2 STREQUAL "HAVE_LIBLCMS2-NOTFOUND") - SET(HAVE_LIBLCMS2 "") - ENDIF() - IF(HAVE_LIBLCMS2) - SET(LCMS_LIB "${HAVE_LIBLCMS2}") - SET(HAVE_LCMS2_LIB 1) - SET(HAVE_LCMS2_H 1) - ENDIF() -ENDIF() -IF(NOT LCMS2_HEADER_FOUND) - FIND_FILE(LCMS1_HEADER_FOUND lcms.h) - IF(LCMS1_HEADER_FOUND STREQUAL "LCMS1_HEADER_FOUND-NOTFOUND") - SET(LCMS1_HEADER_FOUND "") - ENDIF() - IF(LCMS1_HEADER_FOUND) - FIND_PATH(LCMS_INCLUDE_DIR lcms.h) - FIND_LIBRARY(HAVE_LIBLCMS1 lcms) - IF(HAVE_LIBLCMS1 STREQUAL "HAVE_LIBLCMS1-NOTFOUND") - SET(HAVE_LIBLCMS1 "") - ENDIF() - IF(HAVE_LIBLCMS1) - SET(LCMS_LIB "${HAVE_LIBLCMS1}") - SET(HAVE_LCMS1_LIB 1) - SET(HAVE_LCMS1_H 1) - ENDIF() - ENDIF() -ENDIF() + IF(PNG_FOUND) + SET(HAVE_PNG_H 1) + SET(HAVE_LIBPNG 1) + SET(PNG_LIBNAME ${PNG_LIBRARIES}) + SET(PNG_INCLUDE_DIRNAME ${PNG_INCLUDE_DIR}) + ENDIF(PNG_FOUND) +# + FIND_PACKAGE(TIFF QUIET) +# + IF(TIFF_LIBRARY STREQUAL "TIFF_LIBRARY-NOTFOUND") + SET(TIFF_FOUND 0) + ENDIF(TIFF_LIBRARY STREQUAL "TIFF_LIBRARY-NOTFOUND") +# + IF(TIFF_FOUND) + SET(HAVE_TIFF_H 1) + SET(HAVE_LIBTIFF 1) + SET(TIFF_LIBNAME ${TIFF_LIBRARIES}) + SET(TIFF_INCLUDE_DIRNAME ${TIFF_INCLUDE_DIR}) + ENDIF(TIFF_FOUND) +# + FIND_PACKAGE(LCMS QUIET) +# + IF(LCMS_LIBRARY STREQUAL "LCMS_LIBRARY-NOTFOUND") + SET(LCMS_FOUND 0) + ENDIF(LCMS_LIBRARY STREQUAL "LCMS_LIBRARY-NOTFOUND") +# + IF(LCMS_FOUND) + SET(HAVE_LCMS1_H 1) + SET(HAVE_LCMS1_LIB 1) + SET(LCMS_LIBNAME ${LCMS_LIBRARIES}) + SET(LCMS_INCLUDE_DIRNAME ${LCMS_INCLUDE_DIR}) + ENDIF(LCMS_FOUND) +# + IF(NOT LCMS_FOUND) + FIND_PACKAGE(LCMS2 QUIET) + IF(LCMS2_LIBRARY STREQUAL "LCMS2_LIBRARY-NOTFOUND") + SET(LCMS2_FOUND 0) + ENDIF(LCMS2_LIBRARY STREQUAL "LCMS2_LIBRARY-NOTFOUND") +# + IF(LCMS2_FOUND) + SET(HAVE_LCMS2_H 1) + SET(HAVE_LCMS2_LIB 1) + SET(LCMS_LIBNAME ${LCMS2_LIBRARIES}) + SET(LCMS_INCLUDE_DIRNAME ${LCMS2_INCLUDE_DIR}) + ENDIF(LCMS2_FOUND) + ENDIF(NOT LCMS_FOUND) +#------------------------------------------------------------- + OPTION(BUILD_THIRDPARTY "Build the thirdparty executables" ON) +# + IF(NOT ZLIB_FOUND OR NOT PNG_FOUND OR NOT TIFF_FOUND OR NOT LCMS_FOUND OR NOT LCMS2_FOUND) + IF(BUILD_THIRDPARTY) + SET(HAVE_ZLIB_H 1) + SET(HAVE_LIBZ 1) + SET(HAVE_PNG_H 1) + SET(HAVE_LIBPNG 1) + SET(HAVE_TIFF_H 1) + SET(HAVE_LIBTIFF 1) + SET(HAVE_LCMS2_H 1) + SET(HAVE_LIBLCMS2 1) +# + ADD_SUBDIRECTORY(${OPENJPEG_SOURCE_DIR}/thirdparty) +# + LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/thirdparty/lib) +# + IF(NOT ZLIB_FOUND) + INCLUDE_DIRECTORIES(${OPENJPEG_SOURCE_DIR}/thirdparty/include) + SET(ZLIB_INCLUDE_DIRNAME ${OPENJPEG_SOURCE_DIR}/thirdparty/include) + SET(Z_LIBNAME z) + SET(ZLIB_FOUND 1) + ENDIF(NOT ZLIB_FOUND) +# + IF(NOT PNG_FOUND) + SET(PNG_INCLUDE_DIRNAME ${OPENJPEG_SOURCE_DIR}/thirdparty/libpng) + SET(PNG_LIBNAME png) + SET(PNG_FOUND 1) + ENDIF(NOT PNG_FOUND) +# + IF(NOT LCMS_FOUND AND NOT LCMS2_FOUND) + SET(LCMS_INCLUDE_DIRNAME ${OPENJPEG_SOURCE_DIR}/thirdparty/liblcms2/include) + SET(LCMS_LIBNAME lcms2) + SET(LCMS2_FOUND 1) + ENDIF(NOT LCMS_FOUND AND NOT LCMS2_FOUND) +# + IF(NOT TIFF_FOUND) + SET(TIFF_INCLUDE_DIRNAME ${OPENJPEG_SOURCE_DIR}/thirdparty/libtiff) + SET(TIFF_LIBNAME tiff) + SET(TIFF_FOUND 1) + ENDIF(NOT TIFF_FOUND) +# + ENDIF(BUILD_THIRDPARTY) + ENDIF(NOT ZLIB_FOUND OR NOT PNG_FOUND OR NOT TIFF_FOUND OR NOT LCMS_FOUND OR NOT LCMS2_FOUND) +# +ENDIF(BUILD_CODEC OR BUILD_JPWL OR BUILD_MJ2) +# +IF(BUILD_CODEC) + SUBDIRS(codec) +ENDIF(BUILD_CODEC) +# +IF(BUILD_MJ2) + SUBDIRS(mj2) +ENDIF(BUILD_MJ2) +# +IF(BUILD_JPWL) + SUBDIRS(jpwl) +ENDIF(BUILD_JPWL) +# +IF(BUILD_JP3D) + SUBDIRS(jp3d) +ENDIF(BUILD_JP3D) +# +IF(BUILD_INDEXER_JPIP) + SUBDIRS(indexer_JPIP) +ENDIF(BUILD_INDEXER_JPIP) +# +IF(BUILD_DOC) + SUBDIRS(doc) +ENDIF(BUILD_DOC) # # generate opj_config.h CONFIGURE_FILE("${OPENJPEG_SOURCE_DIR}/opj_configh.cmake.in" - "${OPENJPEG_BINARY_DIR}/opj_config.h" - @ONLY + "${OPENJPEG_BINARY_DIR}/opj_config.h" + @ONLY ) - diff --git a/codec/CMakeLists.txt b/codec/CMakeLists.txt index 9b5b70c2..791d13b8 100644 --- a/codec/CMakeLists.txt +++ b/codec/CMakeLists.txt @@ -18,15 +18,12 @@ ENDIF(DONT_HAVE_GETOPT) # Headers file are located here: INCLUDE_DIRECTORIES( ${OPENJPEG_SOURCE_DIR}/libopenjpeg - ${LCMS_INCLUDE_DIR} + ${LCMS_INCLUDE_DIRNAME} ${OPENJPEG_SOURCE_DIR}/common + ${Z_INCLUDE_DIRNAME} + ${PNG_INCLUDE_DIRNAME} + ${TIFF_INCLUDE_DIRNAME} ) -IF(PNG_FOUND) - INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) -ENDIF(PNG_FOUND) -IF(TIFF_FOUND) - INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR}) -ENDIF(TIFF_FOUND) IF(WIN32) IF(BUILD_SHARED_LIBS) @@ -39,13 +36,9 @@ ENDIF(WIN32) # Loop over all executables: FOREACH(exe j2k_to_image image_to_j2k j2k_dump) ADD_EXECUTABLE(${exe} ${exe}.c ${common_SRCS}) - TARGET_LINK_LIBRARIES(${exe} ${OPENJPEG_LIBRARY_NAME} ${LCMS_LIB}) - IF(PNG_FOUND) - TARGET_LINK_LIBRARIES(${exe} ${PNG_LIBRARIES}) - ENDIF(PNG_FOUND) - IF(TIFF_FOUND) - TARGET_LINK_LIBRARIES(${exe} ${TIFF_LIBRARIES}) - ENDIF(TIFF_FOUND) + TARGET_LINK_LIBRARIES(${exe} ${OPENJPEG_LIBRARY_NAME} + ${LCMS_LIBNAME} ${Z_LIBNAME} ${PNG_LIBNAME} ${TIFF_LIBNAME}) + ADD_TEST(${exe} ${EXECUTABLE_OUTPUT_PATH}/${exe}) # calling those exe without option will make them fail always: SET_TESTS_PROPERTIES(${exe} PROPERTIES WILL_FAIL TRUE) diff --git a/codec/convert.c b/codec/convert.c index 088a5c58..47c29931 100644 --- a/codec/convert.c +++ b/codec/convert.c @@ -44,19 +44,12 @@ #endif #ifdef HAVE_LIBTIFF -#ifdef _WIN32 -#include "../libs/libtiff/tiffio.h" -#else #include -#endif /* _WIN32 */ #endif /* HAVE_LIBTIFF */ #ifdef HAVE_LIBPNG -#ifdef _WIN32 -#include "../libs/png/png.h" -#else +#include #include -#endif /* _WIN32 */ #endif /* HAVE_LIBPNG */ #include "../libopenjpeg/openjpeg.h" @@ -1515,7 +1508,7 @@ typedef struct tiff_infoheader{ int imagetotif(opj_image_t * image, const char *outfile) { int width, height, imgsize; int bps,index,adjust = 0; - int last_i=0; + unsigned int last_i=0; TIFF *tif; tdata_t buf; tstrip_t strip; diff --git a/jpwl/CMakeLists.txt b/jpwl/CMakeLists.txt index 783921d7..7dbb3d68 100755 --- a/jpwl/CMakeLists.txt +++ b/jpwl/CMakeLists.txt @@ -39,7 +39,8 @@ IF(WIN32) ENDIF(BUILD_SHARED_LIBS) ENDIF(WIN32) ADD_LIBRARY(${OPENJPEG_LIBRARY_NAME}_JPWL ${JPWL_SRCS} ${OPJ_SRCS}) -SET_TARGET_PROPERTIES(${OPENJPEG_LIBRARY_NAME}_JPWL PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) +SET_TARGET_PROPERTIES(${OPENJPEG_LIBRARY_NAME}_JPWL + PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) # Install library INSTALL(TARGETS ${OPENJPEG_LIBRARY_NAME}_JPWL @@ -51,19 +52,12 @@ INSTALL(TARGETS ${OPENJPEG_LIBRARY_NAME}_JPWL INCLUDE_DIRECTORIES( ${OPENJPEG_SOURCE_DIR}/libopenjpeg ${OPENJPEG_SOURCE_DIR}/common + ${ZLIB_INCLUDE_DIRNAME} + ${LCMS_INCLUDE_DIRNAME} + ${PNG_INCLUDE_DIRNAME} + ${TIFF_INCLUDE_DIRNAME} ) -IF(LCMS_INCLUDE_DIR) - INCLUDE_DIRECTORIES( ${LCMS_INCLUDE_DIR} ) -ENDIF(LCMS_INCLUDE_DIR) -IF(PNG_FOUND) - INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) -ENDIF(PNG_FOUND) -IF(TIFF_FOUND) - INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR}) -ENDIF(TIFF_FOUND) - - ADD_EXECUTABLE(JPWL_j2k_to_image ../codec/j2k_to_image.c ../codec/convert.c @@ -72,13 +66,9 @@ ${OPENJPEG_SOURCE_DIR}/common/color.c ${common_SRCS} ) -TARGET_LINK_LIBRARIES(JPWL_j2k_to_image ${OPENJPEG_LIBRARY_NAME}_JPWL ${LCMS_LIB}) -IF(PNG_FOUND) - TARGET_LINK_LIBRARIES(JPWL_j2k_to_image ${PNG_LIBRARIES}) -ENDIF(PNG_FOUND) -IF(TIFF_FOUND) - TARGET_LINK_LIBRARIES(JPWL_j2k_to_image ${TIFF_LIBRARIES}) -ENDIF(TIFF_FOUND) +TARGET_LINK_LIBRARIES(JPWL_j2k_to_image ${OPENJPEG_LIBRARY_NAME}_JPWL + ${LCMS_LIBNAME} ${Z_LIBNAME} ${PNG_LIBNAME} ${TIFF_LIBNAME}) +# IF(UNIX) TARGET_LINK_LIBRARIES(JPWL_j2k_to_image m) ENDIF(UNIX) @@ -91,13 +81,9 @@ ADD_EXECUTABLE(JPWL_image_to_j2k ${common_SRCS} ) -TARGET_LINK_LIBRARIES(JPWL_image_to_j2k ${OPENJPEG_LIBRARY_NAME}_JPWL ${LCMS_LIB}) -IF(PNG_FOUND) - TARGET_LINK_LIBRARIES(JPWL_image_to_j2k ${PNG_LIBRARIES}) -ENDIF(PNG_FOUND) -IF(TIFF_FOUND) - TARGET_LINK_LIBRARIES(JPWL_image_to_j2k ${TIFF_LIBRARIES}) -ENDIF(TIFF_FOUND) +TARGET_LINK_LIBRARIES(JPWL_image_to_j2k ${OPENJPEG_LIBRARY_NAME}_JPWL + ${LCMS_LIBNAME} ${Z_LIBNAME} ${PNG_LIBNAME} ${TIFF_LIBNAME}) +# IF(UNIX) TARGET_LINK_LIBRARIES(JPWL_image_to_j2k m) ENDIF(UNIX) diff --git a/libs/lcms2/lcms2_static.lib b/libs/lcms2/lcms2_static.lib deleted file mode 100755 index 3256a167d3a16d6533f65d01482a4a361267c63b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1312736 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 diff --git a/libs/libtiff/libtiff.lib b/libs/libtiff/libtiff.lib deleted file mode 100644 index b050b61f0dec2bf7087beb8343171a9d4f0e0845..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 543310 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 -# ifdef __WIN32__ -DECLARE_HANDLE(thandle_t); /* Win32 file handle */ -# else -typedef HFILE thandle_t; /* client data handle */ -# endif /* __WIN32__ */ -#else -typedef void* thandle_t; /* client data handle */ -#endif /* USE_WIN32_FILEIO */ - -/* - * Flags to pass to TIFFPrintDirectory to control - * printing of data structures that are potentially - * very large. Bit-or these flags to enable printing - * multiple items. - */ -#define TIFFPRINT_NONE 0x0 /* no extra info */ -#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ -#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ -#define TIFFPRINT_COLORMAP 0x4 /* colormap */ -#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ -#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ -#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ - -/* - * Colour conversion stuff - */ - -/* reference white */ -#define D65_X0 (95.0470F) -#define D65_Y0 (100.0F) -#define D65_Z0 (108.8827F) - -#define D50_X0 (96.4250F) -#define D50_Y0 (100.0F) -#define D50_Z0 (82.4680F) - -/* Structure for holding information about a display device. */ - -typedef unsigned char TIFFRGBValue; /* 8-bit samples */ - -typedef struct { - float d_mat[3][3]; /* XYZ -> luminance matrix */ - float d_YCR; /* Light o/p for reference white */ - float d_YCG; - float d_YCB; - uint32 d_Vrwr; /* Pixel values for ref. white */ - uint32 d_Vrwg; - uint32 d_Vrwb; - float d_Y0R; /* Residual light for black pixel */ - float d_Y0G; - float d_Y0B; - float d_gammaR; /* Gamma values for the three guns */ - float d_gammaG; - float d_gammaB; -} TIFFDisplay; - -typedef struct { /* YCbCr->RGB support */ - TIFFRGBValue* clamptab; /* range clamping table */ - int* Cr_r_tab; - int* Cb_b_tab; - int32* Cr_g_tab; - int32* Cb_g_tab; - int32* Y_tab; -} TIFFYCbCrToRGB; - -typedef struct { /* CIE Lab 1976->RGB support */ - int range; /* Size of conversion table */ -#define CIELABTORGB_TABLE_RANGE 1500 - float rstep, gstep, bstep; - float X0, Y0, Z0; /* Reference white point */ - TIFFDisplay display; - float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ - float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ - float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ -} TIFFCIELabToRGB; - -/* - * RGBA-style image support. - */ -typedef struct _TIFFRGBAImage TIFFRGBAImage; -/* - * The image reading and conversion routines invoke - * ``put routines'' to copy/image/whatever tiles of - * raw image data. A default set of routines are - * provided to convert/copy raw image data to 8-bit - * packed ABGR format rasters. Applications can supply - * alternate routines that unpack the data into a - * different format or, for example, unpack the data - * and draw the unpacked raster on the display. - */ -typedef void (*tileContigRoutine) - (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, - unsigned char*); -typedef void (*tileSeparateRoutine) - (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, - unsigned char*, unsigned char*, unsigned char*, unsigned char*); -/* - * RGBA-reader state. - */ -struct _TIFFRGBAImage { - TIFF* tif; /* image handle */ - int stoponerr; /* stop on read error */ - int isContig; /* data is packed/separate */ - int alpha; /* type of alpha data present */ - uint32 width; /* image width */ - uint32 height; /* image height */ - uint16 bitspersample; /* image bits/sample */ - uint16 samplesperpixel; /* image samples/pixel */ - uint16 orientation; /* image orientation */ - uint16 req_orientation; /* requested orientation */ - uint16 photometric; /* image photometric interp */ - uint16* redcmap; /* colormap pallete */ - uint16* greencmap; - uint16* bluecmap; - /* get image data routine */ - int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); - /* put decoded strip/tile */ - union { - void (*any)(TIFFRGBAImage*); - tileContigRoutine contig; - tileSeparateRoutine separate; - } put; - TIFFRGBValue* Map; /* sample mapping array */ - uint32** BWmap; /* black&white map */ - uint32** PALmap; /* palette image map */ - TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ - TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ - - uint8* UaToAa; /* Unassociated alpha to associated alpha convertion LUT */ - uint8* Bitdepth16To8; /* LUT for conversion from 16bit to 8bit values */ - - int row_offset; - int col_offset; -}; - -/* - * Macros for extracting components from the - * packed ABGR form returned by TIFFReadRGBAImage. - */ -#define TIFFGetR(abgr) ((abgr) & 0xff) -#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) -#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) -#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) - -/* - * A CODEC is a software package that implements decoding, - * encoding, or decoding+encoding of a compression algorithm. - * The library provides a collection of builtin codecs. - * More codecs may be registered through calls to the library - * and/or the builtin implementations may be overridden. - */ -typedef int (*TIFFInitMethod)(TIFF*, int); -typedef struct { - char* name; - uint16 scheme; - TIFFInitMethod init; -} TIFFCodec; - -#include -#include - -/* share internal LogLuv conversion routines? */ -#ifndef LOGLUV_PUBLIC -#define LOGLUV_PUBLIC 1 -#endif - -#if !defined(__GNUC__) && !defined(__attribute__) -# define __attribute__(x) /*nothing*/ -#endif - -#if defined(c_plusplus) || defined(__cplusplus) -extern "C" { -#endif -typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); -typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); -typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t); -typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); -typedef int (*TIFFCloseProc)(thandle_t); -typedef toff_t (*TIFFSizeProc)(thandle_t); -typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size); -typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size); -typedef void (*TIFFExtendProc)(TIFF*); - -extern const char* TIFFGetVersion(void); - -extern const TIFFCodec* TIFFFindCODEC(uint16); -extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); -extern void TIFFUnRegisterCODEC(TIFFCodec*); -extern int TIFFIsCODECConfigured(uint16); -extern TIFFCodec* TIFFGetConfiguredCODECs(void); - -/* - * Auxiliary functions. - */ - -extern void* _TIFFmalloc(tmsize_t s); -extern void* _TIFFrealloc(void* p, tmsize_t s); -extern void _TIFFmemset(void* p, int v, tmsize_t c); -extern void _TIFFmemcpy(void* d, const void* s, tmsize_t c); -extern int _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c); -extern void _TIFFfree(void* p); - -/* -** Stuff, related to tag handling and creating custom tags. -*/ -extern int TIFFGetTagListCount( TIFF * ); -extern uint32 TIFFGetTagListEntry( TIFF *, int tag_index ); - -#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ -#define TIFF_VARIABLE -1 /* marker for variable length tags */ -#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ -#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ - -#define FIELD_CUSTOM 65 - -typedef struct _TIFFField TIFFField; -typedef struct _TIFFFieldArray TIFFFieldArray; - -extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType); -extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32); -extern const TIFFField* TIFFFieldWithName(TIFF*, const char *); - -typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list); -typedef int (*TIFFVGetMethod)(TIFF*, uint32, va_list); -typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); - -typedef struct { - TIFFVSetMethod vsetfield; /* tag set routine */ - TIFFVGetMethod vgetfield; /* tag get routine */ - TIFFPrintMethod printdir; /* directory print routine */ -} TIFFTagMethods; - -extern TIFFTagMethods *TIFFAccessTagMethods(TIFF *); -extern void *TIFFGetClientInfo(TIFF *, const char *); -extern void TIFFSetClientInfo(TIFF *, void *, const char *); - -extern void TIFFCleanup(TIFF* tif); -extern void TIFFClose(TIFF* tif); -extern int TIFFFlush(TIFF* tif); -extern int TIFFFlushData(TIFF* tif); -extern int TIFFGetField(TIFF* tif, uint32 tag, ...); -extern int TIFFVGetField(TIFF* tif, uint32 tag, va_list ap); -extern int TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...); -extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap); -extern int TIFFReadDirectory(TIFF* tif); -extern int TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, const TIFFFieldArray* infoarray); -extern int TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff); -extern uint64 TIFFScanlineSize64(TIFF* tif); -extern tmsize_t TIFFScanlineSize(TIFF* tif); -extern uint64 TIFFRasterScanlineSize64(TIFF* tif); -extern tmsize_t TIFFRasterScanlineSize(TIFF* tif); -extern uint64 TIFFStripSize64(TIFF* tif); -extern tmsize_t TIFFStripSize(TIFF* tif); -extern uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip); -extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32 strip); -extern uint64 TIFFVStripSize64(TIFF* tif, uint32 nrows); -extern tmsize_t TIFFVStripSize(TIFF* tif, uint32 nrows); -extern uint64 TIFFTileRowSize64(TIFF* tif); -extern tmsize_t TIFFTileRowSize(TIFF* tif); -extern uint64 TIFFTileSize64(TIFF* tif); -extern tmsize_t TIFFTileSize(TIFF* tif); -extern uint64 TIFFVTileSize64(TIFF* tif, uint32 nrows); -extern tmsize_t TIFFVTileSize(TIFF* tif, uint32 nrows); -extern uint32 TIFFDefaultStripSize(TIFF* tif, uint32 request); -extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); -extern int TIFFFileno(TIFF*); -extern int TIFFSetFileno(TIFF*, int); -extern thandle_t TIFFClientdata(TIFF*); -extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); -extern int TIFFGetMode(TIFF*); -extern int TIFFSetMode(TIFF*, int); -extern int TIFFIsTiled(TIFF*); -extern int TIFFIsByteSwapped(TIFF*); -extern int TIFFIsUpSampled(TIFF*); -extern int TIFFIsMSB2LSB(TIFF*); -extern int TIFFIsBigEndian(TIFF*); -extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); -extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); -extern TIFFSeekProc TIFFGetSeekProc(TIFF*); -extern TIFFCloseProc TIFFGetCloseProc(TIFF*); -extern TIFFSizeProc TIFFGetSizeProc(TIFF*); -extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); -extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); -extern uint32 TIFFCurrentRow(TIFF*); -extern uint16 TIFFCurrentDirectory(TIFF*); -extern uint16 TIFFNumberOfDirectories(TIFF*); -extern uint64 TIFFCurrentDirOffset(TIFF*); -extern uint32 TIFFCurrentStrip(TIFF*); -extern uint32 TIFFCurrentTile(TIFF* tif); -extern int TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size); -extern int TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size); -extern int TIFFSetupStrips(TIFF *); -extern int TIFFWriteCheck(TIFF*, int, const char *); -extern void TIFFFreeDirectory(TIFF*); -extern int TIFFCreateDirectory(TIFF*); -extern int TIFFLastDirectory(TIFF*); -extern int TIFFSetDirectory(TIFF*, uint16); -extern int TIFFSetSubDirectory(TIFF*, uint64); -extern int TIFFUnlinkDirectory(TIFF*, uint16); -extern int TIFFSetField(TIFF*, uint32, ...); -extern int TIFFVSetField(TIFF*, uint32, va_list); -extern int TIFFUnsetField(TIFF*, uint32); -extern int TIFFWriteDirectory(TIFF *); -extern int TIFFCheckpointDirectory(TIFF *); -extern int TIFFRewriteDirectory(TIFF *); - -#if defined(c_plusplus) || defined(__cplusplus) -extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); -extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); -extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); -extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); -extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, - int = ORIENTATION_BOTLEFT, int = 0); -#else -extern void TIFFPrintDirectory(TIFF*, FILE*, long); -extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); -extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); -extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); -extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); -#endif - -extern int TIFFReadRGBAStrip(TIFF*, uint32, uint32 * ); -extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); -extern int TIFFRGBAImageOK(TIFF*, char [1024]); -extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); -extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); -extern void TIFFRGBAImageEnd(TIFFRGBAImage*); -extern TIFF* TIFFOpen(const char*, const char*); -# ifdef __WIN32__ -extern TIFF* TIFFOpenW(const wchar_t*, const char*); -# endif /* __WIN32__ */ -extern TIFF* TIFFFdOpen(int, const char*, const char*); -extern TIFF* TIFFClientOpen(const char*, const char*, - thandle_t, - TIFFReadWriteProc, TIFFReadWriteProc, - TIFFSeekProc, TIFFCloseProc, - TIFFSizeProc, - TIFFMapFileProc, TIFFUnmapFileProc); -extern const char* TIFFFileName(TIFF*); -extern const char* TIFFSetFileName(TIFF*, const char *); -extern void TIFFError(const char*, const char*, ...) __attribute__((format (printf,2,3))); -extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); -extern void TIFFWarning(const char*, const char*, ...) __attribute__((format (printf,2,3))); -extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); -extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); -extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); -extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); -extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); -extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); -extern uint32 TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); -extern int TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); -extern uint32 TIFFNumberOfTiles(TIFF*); -extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); -extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); -extern uint32 TIFFComputeStrip(TIFF*, uint32, uint16); -extern uint32 TIFFNumberOfStrips(TIFF*); -extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); -extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); -extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); -extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); -extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); -extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); -extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); -extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); -extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ -extern void TIFFSetWriteOffset(TIFF* tif, toff_t off); -extern void TIFFSwabShort(uint16*); -extern void TIFFSwabLong(uint32*); -extern void TIFFSwabLong8(uint64*); -extern void TIFFSwabFloat(float*); -extern void TIFFSwabDouble(double*); -extern void TIFFSwabArrayOfShort(uint16* wp, tmsize_t n); -extern void TIFFSwabArrayOfTriples(uint8* tp, tmsize_t n); -extern void TIFFSwabArrayOfLong(uint32* lp, tmsize_t n); -extern void TIFFSwabArrayOfLong8(uint64* lp, tmsize_t n); -extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n); -extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n); -extern void TIFFReverseBits(uint8* cp, tmsize_t n); -extern const unsigned char* TIFFGetBitRevTable(int); - -#ifdef LOGLUV_PUBLIC -#define U_NEU 0.210526316 -#define V_NEU 0.473684211 -#define UVSCALE 410. -extern double LogL16toY(int); -extern double LogL10toY(int); -extern void XYZtoRGB24(float*, uint8*); -extern int uv_decode(double*, double*, int); -extern void LogLuv24toXYZ(uint32, float*); -extern void LogLuv32toXYZ(uint32, float*); -#if defined(c_plusplus) || defined(__cplusplus) -extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); -extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); -extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); -extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); -extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); -#else -extern int LogL16fromY(double, int); -extern int LogL10fromY(double, int); -extern int uv_encode(double, double, int); -extern uint32 LogLuv24fromXYZ(float*, int); -extern uint32 LogLuv32fromXYZ(float*, int); -#endif -#endif /* LOGLUV_PUBLIC */ - -extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const TIFFDisplay *, float*); -extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, - float *, float *, float *); -extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, - uint32 *, uint32 *, uint32 *); - -extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); -extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, - uint32 *, uint32 *, uint32 *); - -/**************************************************************************** - * O B S O L E T E D I N T E R F A C E S - * - * Don't use this stuff in your applications, it may be removed in the future - * libtiff versions. - ****************************************************************************/ -typedef struct { - ttag_t field_tag; /* field's tag */ - short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ - short field_writecount; /* write count/TIFF_VARIABLE */ - TIFFDataType field_type; /* type of associated data */ - unsigned short field_bit; /* bit in fieldsset bit vector */ - unsigned char field_oktochange; /* if true, can change while writing */ - unsigned char field_passcount; /* if true, pass dir count on set */ - char *field_name; /* ASCII name */ -} TIFFFieldInfo; - -extern int TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], uint32); -extern const TIFFFieldInfo* TIFFFindFieldInfo(TIFF*, uint32, TIFFDataType); -extern const TIFFFieldInfo* TIFFFindFieldInfoByName(TIFF* , const char *, - TIFFDataType); - -#if defined(c_plusplus) || defined(__cplusplus) -} -#endif - -#endif /* _TIFFIO_ */ - -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/libs/png/libpng14.lib b/libs/png/libpng14.lib deleted file mode 100755 index 6f82f34e29626678f762744a7ba62e5422484ab0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 800554 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

fRi%uGYLV?z+c_ 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

lhjfoE(lQoBAO!ppQ6VD-K259Cj<((Y3 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�N-fvUH1q0MuG3`Kgic>Hkd6>Te@k# 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 XJ@ImU>(xYI{DQ71Z9tImrJDnXP!O diff --git a/libs/png/zlib.lib b/libs/png/zlib.lib deleted file mode 100755 index f534e8f1cb171f38ef2ccc140ba23a60a7934962..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240696 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 diff --git a/mj2/CMakeLists.txt b/mj2/CMakeLists.txt index f7ea0e2e..6fd63dde 100644 --- a/mj2/CMakeLists.txt +++ b/mj2/CMakeLists.txt @@ -37,7 +37,7 @@ ENDIF(WIN32) INCLUDE_DIRECTORIES( ${OPENJPEG_SOURCE_DIR}/libopenjpeg ${OPENJPEG_SOURCE_DIR}/common - ${LCMS_INCLUDE_DIR} + ${LCMS_INCLUDE_DIRNAME} ) ADD_EXECUTABLE(frames_to_mj2 @@ -46,7 +46,9 @@ ADD_EXECUTABLE(frames_to_mj2 ${OPJ_SRCS} ${MJ2_SRCS} ) -TARGET_LINK_LIBRARIES(frames_to_mj2 ${LCMS_LIB}) +IF(LCMS_FOUND OR LCMS2_FOUND) + TARGET_LINK_LIBRARIES(frames_to_mj2 ${LCMS_LIBNAME}) +ENDIF(LCMS_FOUND OR LCMS2_FOUND) IF(UNIX) TARGET_LINK_LIBRARIES(frames_to_mj2 m) ENDIF(UNIX) @@ -58,7 +60,9 @@ ADD_EXECUTABLE(mj2_to_frames ${MJ2_SRCS} ${OPENJPEG_SOURCE_DIR}/common/color.c ) -TARGET_LINK_LIBRARIES(mj2_to_frames ${LCMS_LIB}) +IF(LCMS_FOUND OR LCMS2_FOUND) + TARGET_LINK_LIBRARIES(mj2_to_frames ${LCMS_LIBNAME}) +ENDIF(LCMS_FOUND OR LCMS2_FOUND) IF(UNIX) TARGET_LINK_LIBRARIES(mj2_to_frames m) ENDIF(UNIX) @@ -68,7 +72,9 @@ ADD_EXECUTABLE(extract_j2k_from_mj2 ${OPJ_SRCS} ${MJ2_SRCS} ) -TARGET_LINK_LIBRARIES(extract_j2k_from_mj2 ${LCMS_LIB}) +IF(LCMS_FOUND OR LCMS2_FOUND) + TARGET_LINK_LIBRARIES(extract_j2k_from_mj2 ${LCMS_LIBNAME}) +ENDIF(LCMS_FOUND OR LCMS2_FOUND) IF(UNIX) TARGET_LINK_LIBRARIES(extract_j2k_from_mj2 m) ENDIF(UNIX) @@ -78,7 +84,9 @@ ADD_EXECUTABLE(wrap_j2k_in_mj2 ${OPJ_SRCS} ${MJ2_SRCS} ) -TARGET_LINK_LIBRARIES(wrap_j2k_in_mj2 ${LCMS_LIB}) +IF(LCMS_FOUND OR LCMS2_FOUND) + TARGET_LINK_LIBRARIES(wrap_j2k_in_mj2 ${LCMS_LIBNAME}) +ENDIF(LCMS_FOUND OR LCMS2_FOUND) IF(UNIX) TARGET_LINK_LIBRARIES(wrap_j2k_in_mj2 m) ENDIF(UNIX) diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt new file mode 100644 index 00000000..08710380 --- /dev/null +++ b/thirdparty/CMakeLists.txt @@ -0,0 +1,20 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +IF(BUILD_THIRDPARTY) +# +IF(NOT ZLIB_FOUND) + ADD_SUBDIRECTORY(libz) +ENDIF(NOT ZLIB_FOUND) +# +IF(NOT PNG_FOUND) + ADD_SUBDIRECTORY(libpng) +ENDIF(NOT PNG_FOUND) +# +IF(NOT LCMS2_FOUND) + ADD_SUBDIRECTORY(liblcms2) +ENDIF(NOT LCMS2_FOUND) +# +IF(NOT TIFF_FOUND) + ADD_SUBDIRECTORY(libtiff) +ENDIF(NOT TIFF_FOUND) +# +ENDIF(BUILD_THIRDPARTY) diff --git a/libs/png/zconf.h b/thirdparty/include/zconf.h old mode 100755 new mode 100644 similarity index 65% rename from libs/png/zconf.h rename to thirdparty/include/zconf.h index e3b0c962..02ce56c4 --- a/libs/png/zconf.h +++ b/thirdparty/include/zconf.h @@ -1,332 +1,428 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/thirdparty/include/zconf.h.cmake.msvc b/thirdparty/include/zconf.h.cmake.msvc new file mode 100644 index 00000000..57465e07 --- /dev/null +++ b/thirdparty/include/zconf.h.cmake.msvc @@ -0,0 +1,430 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +/* #undef Z_PREFIX */ +/* #undef Z_HAVE_UNISTD_H */ + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/libs/png/zlib.h b/thirdparty/include/zlib.h old mode 100755 new mode 100644 similarity index 50% rename from libs/png/zlib.h rename to thirdparty/include/zlib.h index 62d0e467..bfbba83e --- a/libs/png/zlib.h +++ b/thirdparty/include/zlib.h @@ -1,1357 +1,1613 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.5, April 19th, 2010 + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.5" +#define ZLIB_VERNUM 0x1250 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is never required, but can be + used to inform inflate that a faster approach may be used for the single + inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK or Z_TREES is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been + found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the + success case, the application may save the current current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef voidp gzFile; /* opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) Also "a" + can be used instead of "w" to request that the gzip stream that will be + written be appended to the file. "+" will result in an error, since reading + and writing to the same gzip file is not supported. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file was not in gzip format, gzread copies the given number of + bytes into the buffer. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream, or failing that, reading the rest + of the input file directly without decompression. The entire input file + will be read if gzread is called until it returns less than the requested + len. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. This state can change from + false to true while reading the input file if the end of a gzip stream is + reached, but is followed by data that is not another gzip stream. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# ifdef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/thirdparty/liblcms2/CMakeLists.txt b/thirdparty/liblcms2/CMakeLists.txt new file mode 100644 index 00000000..e05a42b7 --- /dev/null +++ b/thirdparty/liblcms2/CMakeLists.txt @@ -0,0 +1,20 @@ +PROJECT(liblcms2 C) +# +INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/include") +# +FILE(GLOB SRCS src/*.c) +FILE(GLOB HDRS include/*.h) +# +SET(LIBTARGET "lcms2") +# +ADD_LIBRARY(${LIBTARGET} STATIC ${SRCS} ${HDRS}) +# +IF(MSVC) + SET_TARGET_PROPERTIES(${LIBTARGET} PROPERTIES PREFIX "lib") +ENDIF(MSVC) +# +SET_TARGET_PROPERTIES(${LIBTARGET} + PROPERTIES + OUTPUT_NAME "${LIBTARGET}" + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/thirdparty/lib) +# diff --git a/thirdparty/liblcms2/COPYING b/thirdparty/liblcms2/COPYING new file mode 100644 index 00000000..b147b1b9 --- /dev/null +++ b/thirdparty/liblcms2/COPYING @@ -0,0 +1,8 @@ +Little CMS +Copyright (c) 1998-2010 Marti Maria Saguer + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libs/lcms2/lcms2.h b/thirdparty/liblcms2/include/lcms2.h old mode 100755 new mode 100644 similarity index 98% rename from libs/lcms2/lcms2.h rename to thirdparty/liblcms2/include/lcms2.h index 75a3857a..ef121cba --- a/libs/lcms2/lcms2.h +++ b/thirdparty/liblcms2/include/lcms2.h @@ -23,7 +23,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.0 +// Version 2.1 // #ifndef _lcms2_H @@ -72,7 +72,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2000 +#define LCMS_VERSION 2010 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -181,12 +181,12 @@ typedef int cmsBool; # define CMS_USE_BIG_ENDIAN 1 #endif -#ifdef TARGET_CPU_PPC +#if TARGET_CPU_PPC # define CMS_USE_BIG_ENDIAN 1 #endif #ifdef macintosh -# ifndef __LITTLE_ENDIAN__ +# ifdef __BIG_ENDIAN__ # define CMS_USE_BIG_ENDIAN 1 # endif #endif @@ -380,7 +380,7 @@ typedef enum { cmsSigMotionPictureFilmScanner = 0x6D706673, // 'mpfs' cmsSigMotionPictureFilmRecorder = 0x6D706672, // 'mpfr' cmsSigDigitalMotionPictureCamera = 0x646D7063, // 'dmpc' - cmsSigDigitalCinemaProjector = 0x64636A70, // 'dcpj' + cmsSigDigitalCinemaProjector = 0x64636A70 // 'dcpj' } cmsTechnologySignature; @@ -441,7 +441,7 @@ typedef enum { cmsSigLinkClass = 0x6C696E6B, // 'link' cmsSigAbstractClass = 0x61627374, // 'abst' cmsSigColorSpaceClass = 0x73706163, // 'spac' - cmsSigNamedColorClass = 0x6e6d636c, // 'nmcl' + cmsSigNamedColorClass = 0x6e6d636c // 'nmcl' } cmsProfileClassSignature; @@ -844,9 +844,12 @@ typedef void* cmsHTRANSFORM; // Float formatters. #define TYPE_XYZ_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_XYZA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_LabA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)) #define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_RGBA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4)) // Floating point formatters. @@ -1307,12 +1310,18 @@ CMSAPI cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignatur CMSAPI void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig); CMSAPI cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data); CMSAPI cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest); +CMSAPI cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig); // Read and write raw data CMSAPI cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize); CMSAPI cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size); // Access header data +#define cmsEmbeddedProfileFalse 0x00000000 +#define cmsEmbeddedProfileTrue 0x00000001 +#define cmsUseAnywhere 0x00000000 +#define cmsUseWithEmbeddedDataOnly 0x00000002 + CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile); CMSAPI void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags); CMSAPI void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID); @@ -1348,9 +1357,9 @@ CMSAPI void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, #define LCMS_USED_AS_OUTPUT 1 #define LCMS_USED_AS_PROOF 2 -CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection); +CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection); CMSAPI cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile); -CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection); +CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection); // Translate form/to our notation to ICC CMSAPI cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation); @@ -1499,7 +1508,6 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, c #define cmsFLAGS_NOOPTIMIZE 0x0100 // Inhibit optimizations #define cmsFLAGS_NULLTRANSFORM 0x0200 // Don't transform anyway - // Proofing flags #define cmsFLAGS_GAMUTCHECK 0x1000 // Out of Gamut alarm #define cmsFLAGS_SOFTPROOFING 0x4000 // Do softproofing @@ -1603,8 +1611,15 @@ CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsM // Adaptation state for absolute colorimetric intent CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); +// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); +// For backwards compatibility +CMSAPI cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat); + + // PostScript ColorRenderingDictionary and ColorSpaceArray ---------------------------------------------------- diff --git a/libs/lcms2/lcms2_plugin.h b/thirdparty/liblcms2/include/lcms2_plugin.h old mode 100755 new mode 100644 similarity index 99% rename from libs/lcms2/lcms2_plugin.h rename to thirdparty/liblcms2/include/lcms2_plugin.h index fd903501..896fa498 --- a/libs/lcms2/lcms2_plugin.h +++ b/thirdparty/liblcms2/include/lcms2_plugin.h @@ -115,6 +115,7 @@ struct _cms_io_handler { cmsContext ContextID; cmsUInt32Number UsedSpace; + cmsUInt32Number ReportedSize; char PhysicalFile[cmsMAX_PATH]; cmsUInt32Number (* Read)(struct _cms_io_handler* iohandler, void *Buffer, @@ -385,8 +386,9 @@ typedef struct _cms_typehandler_struct { void (* FreePtr)(struct _cms_typehandler_struct* self, void *Ptr); - // The calling thread + // Additional parameters used by the calling thread cmsContext ContextID; + cmsUInt32Number ICCVersion; } cmsTagTypeHandler; diff --git a/thirdparty/liblcms2/src/cmscam02.c b/thirdparty/liblcms2/src/cmscam02.c new file mode 100644 index 00000000..08eea16a --- /dev/null +++ b/thirdparty/liblcms2/src/cmscam02.c @@ -0,0 +1,483 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging. + +// ---------- Implementation -------------------------------------------- + +typedef struct { + + cmsFloat64Number XYZ[3]; + cmsFloat64Number RGB[3]; + cmsFloat64Number RGBc[3]; + cmsFloat64Number RGBp[3]; + cmsFloat64Number RGBpa[3]; + cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M; + cmsFloat64Number abC[2]; + cmsFloat64Number abs[2]; + cmsFloat64Number abM[2]; + +} CAM02COLOR; + +typedef struct { + + CAM02COLOR adoptedWhite; + cmsFloat64Number LA, Yb; + cmsFloat64Number F, c, Nc; + cmsUInt32Number surround; + cmsFloat64Number n, Nbb, Ncb, z, FL, D; + + cmsContext ContextID; + +} cmsCIECAM02; + + +static +cmsFloat64Number compute_n(cmsCIECAM02* pMod) +{ + return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]); +} + +static +cmsFloat64Number compute_z(cmsCIECAM02* pMod) +{ + return (1.48 + pow(pMod -> n, 0.5)); +} + +static +cmsFloat64Number computeNbb(cmsCIECAM02* pMod) +{ + return (0.725 * pow((1.0 / pMod -> n), 0.2)); +} + +static +cmsFloat64Number computeFL(cmsCIECAM02* pMod) +{ + cmsFloat64Number k, FL; + + k = 1.0 / ((5.0 * pMod->LA) + 1.0); + FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 * + (pow((1.0 - pow(k, 4.0)), 2.0)) * + (pow((5.0 * pMod->LA), (1.0 / 3.0))); + + return FL; +} + +static +cmsFloat64Number computeD(cmsCIECAM02* pMod) +{ + cmsFloat64Number D; + + D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0))); + + return D; +} + + +static +CAM02COLOR XYZtoCAT02(CAM02COLOR clr) +{ + clr.RGB[0] = (clr.XYZ[0] * 0.7328) + (clr.XYZ[1] * 0.4296) + (clr.XYZ[2] * -0.1624); + clr.RGB[1] = (clr.XYZ[0] * -0.7036) + (clr.XYZ[1] * 1.6975) + (clr.XYZ[2] * 0.0061); + clr.RGB[2] = (clr.XYZ[0] * 0.0030) + (clr.XYZ[1] * 0.0136) + (clr.XYZ[2] * 0.9834); + + return clr; +} + +static +CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + + for (i = 0; i < 3; i++) { + clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] * + (pMod->D / pMod -> adoptedWhite.RGB[i])) + + (1.0 - pMod->D)) * clr.RGB[i]; + } + + return clr; +} + + +static +CAM02COLOR CAT02toHPE(CAM02COLOR clr) +{ + cmsFloat64Number M[9]; + + M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628)); + M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698)); + M[2] =(( 0.38971 * 0.182745) + (0.68898 * 0.072098) + (-0.07868 * 1.015326)); + M[3] =((-0.22981 * 1.096124) + (1.18340 * 0.454369) + ( 0.04641 * -0.009628)); + M[4] =((-0.22981 * -0.278869) + (1.18340 * 0.473533) + ( 0.04641 * -0.005698)); + M[5] =((-0.22981 * 0.182745) + (1.18340 * 0.072098) + ( 0.04641 * 1.015326)); + M[6] =(-0.009628); + M[7] =(-0.005698); + M[8] =( 1.015326); + + clr.RGBp[0] = (clr.RGBc[0] * M[0]) + (clr.RGBc[1] * M[1]) + (clr.RGBc[2] * M[2]); + clr.RGBp[1] = (clr.RGBc[0] * M[3]) + (clr.RGBc[1] * M[4]) + (clr.RGBc[2] * M[5]); + clr.RGBp[2] = (clr.RGBc[0] * M[6]) + (clr.RGBc[1] * M[7]) + (clr.RGBc[2] * M[8]); + + return clr; +} + +static +CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + cmsFloat64Number temp; + + for (i = 0; i < 3; i++) { + if (clr.RGBp[i] < 0) { + + temp = pow((-1.0 * pMod->FL * clr.RGBp[i] / 100.0), 0.42); + clr.RGBpa[i] = (-1.0 * 400.0 * temp) / (temp + 27.13) + 0.1; + } + else { + temp = pow((pMod->FL * clr.RGBp[i] / 100.0), 0.42); + clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1; + } + } + + clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + + (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; + + return clr; +} + +static +CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsFloat64Number a, b, temp, e, t, r2d, d2r; + + a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0); + b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0; + + r2d = (180.0 / 3.141592654); + if (a == 0) { + if (b == 0) clr.h = 0; + else if (b > 0) clr.h = 90; + else clr.h = 270; + } + else if (a > 0) { + temp = b / a; + if (b > 0) clr.h = (r2d * atan(temp)); + else if (b == 0) clr.h = 0; + else clr.h = (r2d * atan(temp)) + 360; + } + else { + temp = b / a; + clr.h = (r2d * atan(temp)) + 180; + } + + d2r = (3.141592654 / 180.0); + e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * + (cos((clr.h * d2r + 2.0)) + 3.8); + + if (clr.h < 20.14) { + temp = ((clr.h + 122.47)/1.2) + ((20.14 - clr.h)/0.8); + clr.H = 300 + (100*((clr.h + 122.47)/1.2)) / temp; + } + else if (clr.h < 90.0) { + temp = ((clr.h - 20.14)/0.8) + ((90.00 - clr.h)/0.7); + clr.H = (100*((clr.h - 20.14)/0.8)) / temp; + } + else if (clr.h < 164.25) { + temp = ((clr.h - 90.00)/0.7) + ((164.25 - clr.h)/1.0); + clr.H = 100 + ((100*((clr.h - 90.00)/0.7)) / temp); + } + else if (clr.h < 237.53) { + temp = ((clr.h - 164.25)/1.0) + ((237.53 - clr.h)/1.2); + clr.H = 200 + ((100*((clr.h - 164.25)/1.0)) / temp); + } + else { + temp = ((clr.h - 237.53)/1.2) + ((360 - clr.h + 20.14)/0.8); + clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp); + } + + clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), + (pMod->c * pMod->z)); + + clr.Q = (4.0 / pMod->c) * pow((clr.J / 100.0), 0.5) * + (pMod->adoptedWhite.A + 4.0) * pow(pMod->FL, 0.25); + + t = (e * pow(((a * a) + (b * b)), 0.5)) / + (clr.RGBpa[0] + clr.RGBpa[1] + + ((21.0 / 20.0) * clr.RGBpa[2])); + + clr.C = pow(t, 0.9) * pow((clr.J / 100.0), 0.5) * + pow((1.64 - pow(0.29, pMod->n)), 0.73); + + clr.M = clr.C * pow(pMod->FL, 0.25); + clr.s = 100.0 * pow((clr.M / clr.Q), 0.5); + + return clr; +} + + +static +CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + + cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r; + d2r = 3.141592654 / 180.0; + + t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) * + (pow((1.64 - pow(0.29, pMod->n)), 0.73)))), + (1.0 / 0.9) ); + e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * + (cos((clr.h * d2r + 2.0)) + 3.8); + + clr.A = pMod->adoptedWhite.A * pow( + (clr.J / 100.0), + (1.0 / (pMod->c * pMod->z))); + + p1 = e / t; + p2 = (clr.A / pMod->Nbb) + 0.305; + p3 = 21.0 / 20.0; + + hr = clr.h * d2r; + + if (fabs(sin(hr)) >= fabs(cos(hr))) { + p4 = p1 / sin(hr); + clr.b = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / + (p4 + (2.0 + p3) * (220.0 / 1403.0) * + (cos(hr) / sin(hr)) - (27.0 / 1403.0) + + p3 * (6300.0 / 1403.0)); + clr.a = clr.b * (cos(hr) / sin(hr)); + } + else { + p5 = p1 / cos(hr); + clr.a = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / + (p5 + (2.0 + p3) * (220.0 / 1403.0) - + ((27.0 / 1403.0) - p3 * (6300.0 / 1403.0)) * + (sin(hr) / cos(hr))); + clr.b = clr.a * (sin(hr) / cos(hr)); + } + + clr.RGBpa[0] = ((460.0 / 1403.0) * p2) + + ((451.0 / 1403.0) * clr.a) + + ((288.0 / 1403.0) * clr.b); + clr.RGBpa[1] = ((460.0 / 1403.0) * p2) - + ((891.0 / 1403.0) * clr.a) - + ((261.0 / 1403.0) * clr.b); + clr.RGBpa[2] = ((460.0 / 1403.0) * p2) - + ((220.0 / 1403.0) * clr.a) - + ((6300.0 / 1403.0) * clr.b); + + return clr; +} + +static +CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + cmsFloat64Number c1; + + for (i = 0; i < 3; i++) { + if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1; + else c1 = 1; + clr.RGBp[i] = c1 * (100.0 / pMod->FL) * + pow(((27.13 * fabs(clr.RGBpa[i] - 0.1)) / + (400.0 - fabs(clr.RGBpa[i] - 0.1))), + (1.0 / 0.42)); + } + + return clr; +} + +static +CAM02COLOR HPEtoCAT02(CAM02COLOR clr) +{ + cmsFloat64Number M[9]; + + M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950)); + M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054)); + M[2] = (( 0.7328 * 0.201908) + (0.4296 * 0.000008) - 0.1624); + M[3] = ((-0.7036 * 1.910197) + (1.6975 * 0.370950)); + M[4] = ((-0.7036 * -1.112124) + (1.6975 * 0.629054)); + M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061); + M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950)); + M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054)); + M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);; + + clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]); + clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]); + clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]); + return clr; +} + + +static +CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + for (i = 0; i < 3; i++) { + clr.RGB[i] = clr.RGBc[i] / + ((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D); + } + return clr; +} + + +static +CAM02COLOR CAT02toXYZ(CAM02COLOR clr) +{ + clr.XYZ[0] = (clr.RGB[0] * 1.096124) + (clr.RGB[1] * -0.278869) + (clr.RGB[2] * 0.182745); + clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098); + clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326); + + return clr; +} + + +cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC) +{ + cmsCIECAM02* lpMod; + + _cmsAssert(pVC != NULL); + + if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) { + return NULL; + } + + lpMod ->ContextID = ContextID; + + lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X; + lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y; + lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z; + + lpMod -> LA = pVC ->La; + lpMod -> Yb = pVC ->Yb; + lpMod -> D = pVC ->D_value; + lpMod -> surround = pVC ->surround; + + switch (lpMod -> surround) { + + + case CUTSHEET_SURROUND: + lpMod->F = 0.8; + lpMod->c = 0.41; + lpMod->Nc = 0.8; + break; + + case DARK_SURROUND: + lpMod -> F = 0.8; + lpMod -> c = 0.525; + lpMod -> Nc = 0.8; + break; + + case DIM_SURROUND: + lpMod -> F = 0.9; + lpMod -> c = 0.59; + lpMod -> Nc = 0.95; + break; + + default: + // Average surround + lpMod -> F = 1.0; + lpMod -> c = 0.69; + lpMod -> Nc = 1.0; + } + + lpMod -> n = compute_n(lpMod); + lpMod -> z = compute_z(lpMod); + lpMod -> Nbb = computeNbb(lpMod); + lpMod -> FL = computeFL(lpMod); + + if (lpMod -> D == D_CALCULATE) { + lpMod -> D = computeD(lpMod); + } + + lpMod -> Ncb = lpMod -> Nbb; + + lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); + lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); + lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); + lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); + + return (cmsHANDLE) lpMod; + +} + +void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel) +{ + cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + + if (lpMod) _cmsFree(lpMod ->ContextID, lpMod); +} + + +void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut) +{ + CAM02COLOR clr; + cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + + _cmsAssert(lpMod != NULL); + _cmsAssert(pIn != NULL); + _cmsAssert(pOut != NULL); + + clr.XYZ[0] = pIn ->X; + clr.XYZ[1] = pIn ->Y; + clr.XYZ[2] = pIn ->Z; + + clr = XYZtoCAT02(clr); + clr = ChromaticAdaptation(clr, lpMod); + clr = CAT02toHPE(clr); + clr = NonlinearCompression(clr, lpMod); + clr = ComputeCorrelates(clr, lpMod); + + pOut ->J = clr.J; + pOut ->C = clr.C; + pOut ->h = clr.h; +} + +void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut) +{ + CAM02COLOR clr; + cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + + _cmsAssert(lpMod != NULL); + _cmsAssert(pIn != NULL); + _cmsAssert(pOut != NULL); + + clr.J = pIn -> J; + clr.C = pIn -> C; + clr.h = pIn -> h; + + clr = InverseCorrelates(clr, lpMod); + clr = InverseNonlinearity(clr, lpMod); + clr = HPEtoCAT02(clr); + clr = InverseChromaticAdaptation(clr, lpMod); + clr = CAT02toXYZ(clr); + + pOut ->X = clr.XYZ[0]; + pOut ->Y = clr.XYZ[1]; + pOut ->Z = clr.XYZ[2]; +} + diff --git a/thirdparty/liblcms2/src/cmscgats.c b/thirdparty/liblcms2/src/cmscgats.c new file mode 100644 index 00000000..d41c15a2 --- /dev/null +++ b/thirdparty/liblcms2/src/cmscgats.c @@ -0,0 +1,2655 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- + + +#define MAXID 128 // Max lenght of identifier +#define MAXSTR 1024 // Max lenght of string +#define MAXTABLES 255 // Max Number of tables in a single stream +#define MAXINCLUDE 20 // Max number of nested includes + +#define DEFAULT_DBL_FORMAT "%.10g" // Double formatting + +#ifdef CMS_IS_WINDOWS_ +# include +# define DIR_CHAR '\\' +#else +# define DIR_CHAR '/' +#endif + +// Symbols +typedef enum { + + SNONE, + SINUM, // Integer + SDNUM, // Real + SIDENT, // Identifier + SSTRING, // string + SCOMMENT, // comment + SEOLN, // End of line + SEOF, // End of stream + SSYNERROR, // Syntax error found on stream + + // Keywords + + SBEGIN_DATA, + SBEGIN_DATA_FORMAT, + SEND_DATA, + SEND_DATA_FORMAT, + SKEYWORD, + SDATA_FORMAT_ID, + SINCLUDE + + } SYMBOL; + + +// How to write the value +typedef enum { + + WRITE_UNCOOKED, + WRITE_STRINGIFY, + WRITE_HEXADECIMAL, + WRITE_BINARY, + WRITE_PAIR + + } WRITEMODE; + +// Linked list of variable names +typedef struct _KeyVal { + + struct _KeyVal* Next; + char* Keyword; // Name of variable + struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item + char* Subkey; // If key is a dictionary, points to the subkey name + char* Value; // Points to value + WRITEMODE WriteAs; // How to write the value + + } KEYVALUE; + + +// Linked list of memory chunks (Memory sink) +typedef struct _OwnedMem { + + struct _OwnedMem* Next; + void * Ptr; // Point to value + + } OWNEDMEM; + +// Suballocator +typedef struct _SubAllocator { + + cmsUInt8Number* Block; + cmsUInt32Number BlockSize; + cmsUInt32Number Used; + + } SUBALLOCATOR; + +// Table. Each individual table can hold properties and rows & cols +typedef struct _Table { + + int nSamples, nPatches; // Cols, Rows + int SampleID; // Pos of ID + + KEYVALUE* HeaderList; // The properties + + char** DataFormat; // The binary stream descriptor + char** Data; // The binary stream + + } TABLE; + +// File stream being parsed +typedef struct _FileContext { + char FileName[cmsMAX_PATH]; // File name if being readed from file + FILE* Stream; // File stream or NULL if holded in memory + } FILECTX; + +// This struct hold all information about an open IT8 handler. +typedef struct { + + char SheetType[MAXSTR]; // The first row of the IT8 (the type) + + cmsUInt32Number TablesCount; // How many tables in this stream + cmsUInt32Number nTable; // The actual table + + TABLE Tab[MAXTABLES]; + + // Memory management + OWNEDMEM* MemorySink; // The storage backend + SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast + + // Parser state machine + SYMBOL sy; // Current symbol + int ch; // Current character + + int inum; // integer value + cmsFloat64Number dnum; // real value + char id[MAXID]; // identifier + char str[MAXSTR]; // string + + // Allowed keywords & datasets. They have visibility on whole stream + KEYVALUE* ValidKeywords; + KEYVALUE* ValidSampleID; + + char* Source; // Points to loc. being parsed + int lineno; // line counter for error reporting + + FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed + int IncludeSP; // Include Stack Pointer + + char* MemoryBlock; // The stream if holded in memory + + char DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter + + cmsContext ContextID; // The threading context + + } cmsIT8; + + +// The stream for save operations +typedef struct { + + FILE* stream; // For save-to-file behaviour + + cmsUInt8Number* Base; + cmsUInt8Number* Ptr; // For save-to-mem behaviour + cmsUInt32Number Used; + cmsUInt32Number Max; + + } SAVESTREAM; + + +// ------------------------------------------------------ cmsIT8 parsing routines + + +// A keyword +typedef struct { + + const char *id; + SYMBOL sy; + + } KEYWORD; + +// The keyword->symbol translation table. Sorting is required. +static const KEYWORD TabKeys[] = { + + {"$INCLUDE", SINCLUDE}, // This is an extension! + {".INCLUDE", SINCLUDE}, // This is an extension! + + {"BEGIN_DATA", SBEGIN_DATA }, + {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT }, + {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID}, + {"END_DATA", SEND_DATA}, + {"END_DATA_FORMAT", SEND_DATA_FORMAT}, + {"KEYWORD", SKEYWORD} + }; + +#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) + +// Predefined properties + +// A property +typedef struct { + const char *id; // The identifier + WRITEMODE as; // How is supposed to be written + } PROPERTY; + +static PROPERTY PredefinedProperties[] = { + + {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS + {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS + {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file. + {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file. + {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal". + {"MANUFACTURER", WRITE_STRINGIFY}, + {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value + {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm. + {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target. + + {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code + // uniquely identifying th e material. This is intend ed to be used for IT8.7 + // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). + + {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and + // model number) to generate the data reported. This data will often + // provide more information about the particular data collected than an + // extensive list of specific details. This is particularly important for + // spectral data or data derived from spectrophotometry. + + {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide + // a guide to the potential for issues of paper fluorescence, etc. + + {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. + // Where standard conditions have been defined (e.g., SWOP at nominal) + // named conditions may suffice. Otherwise, detailed information is + // needed. + + {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during + // measurement. Allowed values are “black”, “white”, or {"na". + + {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic + + // below properties are new in recent specs: + + {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated + // along with details of the geometry and the aperture size and shape. For example, + // for transmission measurements it is important to identify 0/diffuse, diffuse/0, + // opal or integrating sphere, etc. For reflection it is important to identify 0/45, + // 45/0, sphere (specular included or excluded), etc. + + {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to + // denote the use of filters such as none, D65, Red, Green or Blue. + + {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed + // values are {"yes”, “white”, “none” or “na”. + + {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the + // calculation of various data parameters (2 degree and 10 degree), CIE standard + // illuminant functions used in the calculation of various data parameters (e.g., D50, + // D65, etc.), density status response, etc. If used there shall be at least one + // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute + // in the set shall be {"name" and shall identify the particular parameter used. + // The second shall be {"value" and shall provide the value associated with that name. + // For ASCII data, a string containing the Name and Value attribute pairs shall follow + // the weighting function keyword. A semi-colon separates attribute pairs from each + // other and within the attribute the name and value are separated by a comma. + + {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name + // of the calculation, parameter is the name of the parameter used in the calculation + // and value is the value of the parameter. + + {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. + + {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target. + + {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table. + + {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table. +}; + +#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY)) + + +// Predefined sample types on dataset +static const char* PredefinedSampleID[] = { + "SAMPLE_ID", // Identifies sample that data represents + "STRING", // Identifies label, or other non-machine readable value. + // Value must begin and end with a " symbol + + "CMYK_C", // Cyan component of CMYK data expressed as a percentage + "CMYK_M", // Magenta component of CMYK data expressed as a percentage + "CMYK_Y", // Yellow component of CMYK data expressed as a percentage + "CMYK_K", // Black component of CMYK data expressed as a percentage + "D_RED", // Red filter density + "D_GREEN", // Green filter density + "D_BLUE", // Blue filter density + "D_VIS", // Visual filter density + "D_MAJOR_FILTER", // Major filter d ensity + "RGB_R", // Red component of RGB data + "RGB_G", // Green component of RGB data + "RGB_B", // Blue com ponent of RGB data + "SPECTRAL_NM", // Wavelength of measurement expressed in nanometers + "SPECTRAL_PCT", // Percentage reflectance/transmittance + "SPECTRAL_DEC", // Reflectance/transmittance + "XYZ_X", // X component of tristimulus data + "XYZ_Y", // Y component of tristimulus data + "XYZ_Z", // Z component of tristimulus data + "XYY_X" // x component of chromaticity data + "XYY_Y", // y component of chromaticity data + "XYY_CAPY", // Y component of tristimulus data + "LAB_L", // L* component of Lab data + "LAB_A", // a* component of Lab data + "LAB_B", // b* component of Lab data + "LAB_C", // C*ab component of Lab data + "LAB_H", // hab component of Lab data + "LAB_DE", // CIE dE + "LAB_DE_94", // CIE dE using CIE 94 + "LAB_DE_CMC", // dE using CMC + "LAB_DE_2000", // CIE dE using CIE DE 2000 + "MEAN_DE", // Mean Delta E (LAB_DE) of samples compared to batch average + // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets) + "STDEV_X", // Standard deviation of X (tristimulus data) + "STDEV_Y", // Standard deviation of Y (tristimulus data) + "STDEV_Z", // Standard deviation of Z (tristimulus data) + "STDEV_L", // Standard deviation of L* + "STDEV_A", // Standard deviation of a* + "STDEV_B", // Standard deviation of b* + "STDEV_DE", // Standard deviation of CIE dE + "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is + // used to derive an estimate of the chi-squared parameter which is + // recommended as the predictor of the variability of dE + +#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) + +//Forward declaration of some internal functions +static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); + +// Checks if c is a separator +static +cmsBool isseparator(int c) +{ + return (c == ' ') || (c == '\t') || (c == '\r'); +} + +// Checks whatever if c is a valid identifier char +static +cmsBool ismiddle(int c) +{ + return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); +} + +// Checks whatsever if c is a valid identifier middle char. +static +cmsBool isidchar(int c) +{ + return isalnum(c) || ismiddle(c); +} + +// Checks whatsever if c is a valid identifier first char. +static +cmsBool isfirstidchar(int c) +{ + return !isdigit(c) && ismiddle(c); +} + +// Guess whether the supplied path looks like an absolute path +static +cmsBool isabsolutepath(const char *path) +{ + char ThreeChars[4]; + + if(path == NULL) + return FALSE; + if (path[0] == 0) + return FALSE; + + strncpy(ThreeChars, path, 3); + ThreeChars[3] = 0; + + if(ThreeChars[0] == DIR_CHAR) + return TRUE; + +#ifdef CMS_IS_WINDOWS_ + if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':') + return TRUE; +#endif + return FALSE; +} + +// Makes a file path based on a given reference path +// NOTE: this function doesn't check if the path exists or even if it's legal +static +cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen) +{ + char *tail; + cmsUInt32Number len; + + // Already absolute? + if (isabsolutepath(relPath)) { + + strncpy(buffer, relPath, MaxLen); + buffer[MaxLen-1] = 0; + return TRUE; + } + + // No, search for last + strncpy(buffer, basePath, MaxLen); + buffer[MaxLen-1] = 0; + + tail = strrchr(buffer, DIR_CHAR); + if (tail == NULL) return FALSE; // Is not absolute and has no separators?? + + len = (cmsUInt32Number) (tail - buffer); + if (len >= MaxLen) return FALSE; + + // No need to assure zero terminator over here + strncpy(tail + 1, relPath, MaxLen - len); + + return TRUE; +} + + +// Make sure no exploit is being even tried +static +const char* NoMeta(const char* str) +{ + if (strchr(str, '%') != NULL) + return "**** CORRUPTED FORMAT STRING ***"; + + return str; +} + +// Syntax error +static +cmsBool SynError(cmsIT8* it8, const char *Txt, ...) +{ + char Buffer[256], ErrMsg[1024]; + va_list args; + + va_start(args, Txt); + vsnprintf(Buffer, 255, Txt, args); + Buffer[255] = 0; + va_end(args); + + snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer); + ErrMsg[1023] = 0; + it8->sy = SSYNERROR; + cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg); + return FALSE; +} + +// Check if current symbol is same as specified. issue an error else. +static +cmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err) +{ + if (it8 -> sy != sy) + return SynError(it8, NoMeta(Err)); + return TRUE; +} + +// Read Next character from stream +static +void NextCh(cmsIT8* it8) +{ + if (it8 -> FileStack[it8 ->IncludeSP]->Stream) { + + it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream); + + if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) { + + if (it8 ->IncludeSP > 0) { + + fclose(it8 ->FileStack[it8->IncludeSP--]->Stream); + it8 -> ch = ' '; // Whitespace to be ignored + + } else + it8 ->ch = 0; // EOF + } + } + else { + it8->ch = *it8->Source; + if (it8->ch) it8->Source++; + } +} + + +// Try to see if current identifier is a keyword, if so return the referred symbol +static +SYMBOL BinSrchKey(const char *id) +{ + int l = 1; + int r = NUMKEYS; + int x, res; + + while (r >= l) + { + x = (l+r)/2; + res = cmsstrcasecmp(id, TabKeys[x-1].id); + if (res == 0) return TabKeys[x-1].sy; + if (res < 0) r = x - 1; + else l = x + 1; + } + + return SNONE; +} + + +// 10 ^n +static +cmsFloat64Number xpow10(int n) +{ + return pow(10, (cmsFloat64Number) n); +} + + +// Reads a Real number, tries to follow from integer number +static +void ReadReal(cmsIT8* it8, int inum) +{ + it8->dnum = (cmsFloat64Number) inum; + + while (isdigit(it8->ch)) { + + it8->dnum = it8->dnum * 10.0 + (it8->ch - '0'); + NextCh(it8); + } + + if (it8->ch == '.') { // Decimal point + + cmsFloat64Number frac = 0.0; // fraction + int prec = 0; // precision + + NextCh(it8); // Eats dec. point + + while (isdigit(it8->ch)) { + + frac = frac * 10.0 + (it8->ch - '0'); + prec++; + NextCh(it8); + } + + it8->dnum = it8->dnum + (frac / xpow10(prec)); + } + + // Exponent, example 34.00E+20 + if (toupper(it8->ch) == 'E') { + + int e; + int sgn; + + NextCh(it8); sgn = 1; + + if (it8->ch == '-') { + + sgn = -1; NextCh(it8); + } + else + if (it8->ch == '+') { + + sgn = +1; + NextCh(it8); + } + + e = 0; + while (isdigit(it8->ch)) { + + if ((cmsFloat64Number) e * 10L < INT_MAX) + e = e * 10 + (it8->ch - '0'); + + NextCh(it8); + } + + e = sgn*e; + it8 -> dnum = it8 -> dnum * xpow10(e); + } +} + + + +// Reads next symbol +static +void InSymbol(cmsIT8* it8) +{ + register char *idptr; + register int k; + SYMBOL key; + int sng; + + do { + + while (isseparator(it8->ch)) + NextCh(it8); + + if (isfirstidchar(it8->ch)) { // Identifier + + k = 0; + idptr = it8->id; + + do { + + if (++k < MAXID) *idptr++ = (char) it8->ch; + + NextCh(it8); + + } while (isidchar(it8->ch)); + + *idptr = '\0'; + + + key = BinSrchKey(it8->id); + if (key == SNONE) it8->sy = SIDENT; + else it8->sy = key; + + } + else // Is a number? + if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+') + { + int sign = 1; + + if (it8->ch == '-') { + sign = -1; + NextCh(it8); + } + + it8->inum = 0; + it8->sy = SINUM; + + if (it8->ch == '0') { // 0xnnnn (Hexa) or 0bnnnn (Binary) + + NextCh(it8); + if (toupper(it8->ch) == 'X') { + + int j; + + NextCh(it8); + while (isxdigit(it8->ch)) + { + it8->ch = toupper(it8->ch); + if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10; + else j = it8->ch - '0'; + + if ((long) it8->inum * 16L > (long) INT_MAX) + { + SynError(it8, "Invalid hexadecimal number"); + return; + } + + it8->inum = it8->inum * 16 + j; + NextCh(it8); + } + return; + } + + if (toupper(it8->ch) == 'B') { // Binary + + int j; + + NextCh(it8); + while (it8->ch == '0' || it8->ch == '1') + { + j = it8->ch - '0'; + + if ((long) it8->inum * 2L > (long) INT_MAX) + { + SynError(it8, "Invalid binary number"); + return; + } + + it8->inum = it8->inum * 2 + j; + NextCh(it8); + } + return; + } + } + + + while (isdigit(it8->ch)) { + + if ((long) it8->inum * 10L > (long) INT_MAX) { + ReadReal(it8, it8->inum); + it8->sy = SDNUM; + it8->dnum *= sign; + return; + } + + it8->inum = it8->inum * 10 + (it8->ch - '0'); + NextCh(it8); + } + + if (it8->ch == '.') { + + ReadReal(it8, it8->inum); + it8->sy = SDNUM; + it8->dnum *= sign; + return; + } + + it8 -> inum *= sign; + + // Special case. Numbers followed by letters are taken as identifiers + + if (isidchar(it8 ->ch)) { + + if (it8 ->sy == SINUM) { + + sprintf(it8->id, "%d", it8->inum); + } + else { + + sprintf(it8->id, it8 ->DoubleFormatter, it8->dnum); + } + + k = (int) strlen(it8 ->id); + idptr = it8 ->id + k; + do { + + if (++k < MAXID) *idptr++ = (char) it8->ch; + + NextCh(it8); + + } while (isidchar(it8->ch)); + + *idptr = '\0'; + it8->sy = SIDENT; + } + return; + + } + else + switch ((int) it8->ch) { + + // EOF marker -- ignore it + case '\x1a': + NextCh(it8); + break; + + // Eof stream markers + case 0: + case -1: + it8->sy = SEOF; + break; + + + // Next line + case '\n': + NextCh(it8); + it8->sy = SEOLN; + it8->lineno++; + break; + + // Comment + case '#': + NextCh(it8); + while (it8->ch && it8->ch != '\n') + NextCh(it8); + + it8->sy = SCOMMENT; + break; + + // String. + case '\'': + case '\"': + idptr = it8->str; + sng = it8->ch; + k = 0; + NextCh(it8); + + while (k < MAXSTR && it8->ch != sng) { + + if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1; + else { + *idptr++ = (char) it8->ch; + NextCh(it8); + k++; + } + } + + it8->sy = SSTRING; + *idptr = '\0'; + NextCh(it8); + break; + + + default: + SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); + return; + } + + } while (it8->sy == SCOMMENT); + + // Handle the include special token + + if (it8 -> sy == SINCLUDE) { + + FILECTX* FileNest; + + if(it8 -> IncludeSP >= (MAXINCLUDE-1)) { + + SynError(it8, "Too many recursion levels"); + return; + } + + InSymbol(it8); + if (!Check(it8, SSTRING, "Filename expected")) return; + + FileNest = it8 -> FileStack[it8 -> IncludeSP + 1]; + if(FileNest == NULL) { + + FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); + //if(FileNest == NULL) + // TODO: how to manage out-of-memory conditions? + } + + if (BuildAbsolutePath(it8->str, + it8->FileStack[it8->IncludeSP]->FileName, + FileNest->FileName, cmsMAX_PATH-1) == FALSE) { + SynError(it8, "File path too long"); + return; + } + + FileNest->Stream = fopen(FileNest->FileName, "rt"); + if (FileNest->Stream == NULL) { + + SynError(it8, "File %s not found", FileNest->FileName); + return; + } + it8->IncludeSP++; + + it8 ->ch = ' '; + InSymbol(it8); + } + +} + +// Checks end of line separator +static +cmsBool CheckEOLN(cmsIT8* it8) +{ + if (!Check(it8, SEOLN, "Expected separator")) return FALSE; + while (it8 -> sy == SEOLN) + InSymbol(it8); + return TRUE; + +} + +// Skip a symbol + +static +void Skip(cmsIT8* it8, SYMBOL sy) +{ + if (it8->sy == sy && it8->sy != SEOF) + InSymbol(it8); +} + + +// Skip multiple EOLN +static +void SkipEOLN(cmsIT8* it8) +{ + while (it8->sy == SEOLN) { + InSymbol(it8); + } +} + + +// Returns a string holding current value +static +cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle) +{ + switch (it8->sy) { + + case SIDENT: strncpy(Buffer, it8->id, max); + Buffer[max-1]=0; + break; + case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; + case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; + case SSTRING: strncpy(Buffer, it8->str, max); + Buffer[max-1] = 0; + break; + + + default: + return SynError(it8, "%s", ErrorTitle); + } + + Buffer[max] = 0; + return TRUE; +} + +// ---------------------------------------------------------- Table + +static +TABLE* GetTable(cmsIT8* it8) +{ + if ((it8 -> nTable >= it8 ->TablesCount)) { + + SynError(it8, "Table %d out of sequence", it8 -> nTable); + return it8 -> Tab; + } + + return it8 ->Tab + it8 ->nTable; +} + +// ---------------------------------------------------------- Memory management + + +// Frees an allocator and owned memory +void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + if (it8 == NULL) + return; + + if (it8->MemorySink) { + + OWNEDMEM* p; + OWNEDMEM* n; + + for (p = it8->MemorySink; p != NULL; p = n) { + + n = p->Next; + if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr); + _cmsFree(it8 ->ContextID, p); + } + } + + if (it8->MemoryBlock) + _cmsFree(it8 ->ContextID, it8->MemoryBlock); + + _cmsFree(it8 ->ContextID, it8); +} + + +// Allocates a chunk of data, keep linked list +static +void* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size) +{ + OWNEDMEM* ptr1; + void* ptr = _cmsMallocZero(it8->ContextID, size); + + if (ptr != NULL) { + + ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM)); + + if (ptr1 == NULL) { + + _cmsFree(it8 ->ContextID, ptr); + return NULL; + } + + ptr1-> Ptr = ptr; + ptr1-> Next = it8 -> MemorySink; + it8 -> MemorySink = ptr1; + } + + return ptr; +} + + +// Suballocator. +static +void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) +{ + cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used; + cmsUInt8Number* ptr; + + size = _cmsALIGNLONG(size); + + if (size > Free) { + + if (it8 -> Allocator.BlockSize == 0) + + it8 -> Allocator.BlockSize = 20*1024; + else + it8 ->Allocator.BlockSize *= 2; + + if (it8 ->Allocator.BlockSize < size) + it8 ->Allocator.BlockSize = size; + + it8 ->Allocator.Used = 0; + it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize); + } + + ptr = it8 ->Allocator.Block + it8 ->Allocator.Used; + it8 ->Allocator.Used += size; + + return (void*) ptr; + +} + + +// Allocates a string +static +char *AllocString(cmsIT8* it8, const char* str) +{ + cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1; + char *ptr; + + + ptr = (char *) AllocChunk(it8, Size); + if (ptr) strncpy (ptr, str, Size-1); + + return ptr; +} + +// Searches through linked list + +static +cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr) +{ + if (LastPtr) *LastPtr = p; + + for (; p != NULL; p = p->Next) { + + if (LastPtr) *LastPtr = p; + + if (*Key != '#') { // Comments are ignored + + if (cmsstrcasecmp(Key, p->Keyword) == 0) + break; + } + } + + if (p == NULL) + return FALSE; + + if (Subkey == 0) + return TRUE; + + for (; p != NULL; p = p->NextSubkey) { + + if (LastPtr) *LastPtr = p; + + if (cmsstrcasecmp(Subkey, p->Subkey) == 0) + return TRUE; + } + + return FALSE; +} + + + +// Add a property into a linked list +static +KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs) +{ + KEYVALUE* p; + KEYVALUE* last; + + + // Check if property is already in list + + if (IsAvailableOnList(*Head, Key, Subkey, &p)) { + + // This may work for editing properties + + // return SynError(it8, "duplicate key <%s>", Key); + } + else { + + last = p; + + // Allocate the container + p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE)); + if (p == NULL) + { + SynError(it8, "AddToList: out of memory"); + return NULL; + } + + // Store name and value + p->Keyword = AllocString(it8, Key); + p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey); + + // Keep the container in our list + if (*Head == NULL) { + *Head = p; + } + else + { + if (Subkey != NULL && last != NULL) { + + last->NextSubkey = p; + + // If Subkey is not null, then last is the last property with the same key, + // but not necessarily is the last property in the list, so we need to move + // to the actual list end + while (last->Next != NULL) + last = last->Next; + } + + if (last != NULL) last->Next = p; + } + + p->Next = NULL; + p->NextSubkey = NULL; + } + + p->WriteAs = WriteAs; + + if (xValue != NULL) { + + p->Value = AllocString(it8, xValue); + } + else { + p->Value = NULL; + } + + return p; +} + +static +KEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as) +{ + return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as); +} + + +static +KEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key) +{ + return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED); +} + + +static +void AllocTable(cmsIT8* it8) +{ + TABLE* t; + + t = it8 ->Tab + it8 ->TablesCount; + + t->HeaderList = NULL; + t->DataFormat = NULL; + t->Data = NULL; + + it8 ->TablesCount++; +} + + +cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) +{ + cmsIT8* it8 = (cmsIT8*) IT8; + + if (nTable >= it8 ->TablesCount) { + + if (nTable == it8 ->TablesCount) { + + AllocTable(it8); + } + else { + SynError(it8, "Table %d is out of sequence", nTable); + return -1; + } + } + + it8 ->nTable = nTable; + + return nTable; +} + + + +// Init an empty container +cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) +{ + cmsIT8* it8; + int i; + + it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8)); + if (it8 == NULL) return NULL; + + AllocTable(it8); + + it8->MemoryBlock = NULL; + it8->MemorySink = NULL; + + it8 ->nTable = 0; + + it8->ContextID = ContextID; + it8->Allocator.Used = 0; + it8->Allocator.Block = NULL; + it8->Allocator.BlockSize = 0; + + it8->ValidKeywords = NULL; + it8->ValidSampleID = NULL; + + it8 -> sy = SNONE; + it8 -> ch = ' '; + it8 -> Source = NULL; + it8 -> inum = 0; + it8 -> dnum = 0.0; + + it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); + it8->IncludeSP = 0; + it8 -> lineno = 1; + + strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); + strcpy(it8->SheetType, "CGATS.17"); + + // Initialize predefined properties & data + + for (i=0; i < NUMPREDEFINEDPROPS; i++) + AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); + + for (i=0; i < NUMPREDEFINEDSAMPLEID; i++) + AddAvailableSampleID(it8, PredefinedSampleID[i]); + + + return (cmsHANDLE) it8; +} + + +const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + return it8 ->SheetType; + +} + +cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + strncpy(it8 ->SheetType, Type, MAXSTR-1); + it8 ->SheetType[MAXSTR-1] = 0; + return TRUE; +} + +cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + if (!Val) return FALSE; + if (!*Val) return FALSE; + + return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; +} + + + +// Sets a property +cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + if (!Val) return FALSE; + if (!*Val) return FALSE; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; +} + + +cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buffer[1024]; + + sprintf(Buffer, it8->DoubleFormatter, Val); + + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buffer[1024]; + + sprintf(Buffer, "%d", Val); + + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL; +} + +// Gets a property +const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE* p; + + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p)) + { + return p -> Value; + } + return NULL; +} + + +cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp) +{ + const char *v = cmsIT8GetProperty(hIT8, cProp); + + if (v) return atof(v); + else return 0.0; +} + +const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE* p; + + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) { + return p -> Value; + } + return NULL; +} + +// ----------------------------------------------------------------- Datasets + + +static +void AllocateDataFormat(cmsIT8* it8) +{ + TABLE* t = GetTable(it8); + + if (t -> DataFormat) return; // Already allocated + + t -> nSamples = (int) cmsIT8GetPropertyDbl(it8, "NUMBER_OF_FIELDS"); + + if (t -> nSamples <= 0) { + + SynError(it8, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS"); + t -> nSamples = 10; + } + + t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *)); + if (t->DataFormat == NULL) { + + SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); + } + +} + +static +const char *GetDataFormat(cmsIT8* it8, int n) +{ + TABLE* t = GetTable(it8); + + if (t->DataFormat) + return t->DataFormat[n]; + + return NULL; +} + +static +cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) +{ + TABLE* t = GetTable(it8); + + if (!t->DataFormat) + AllocateDataFormat(it8); + + if (n > t -> nSamples) { + SynError(it8, "More than NUMBER_OF_FIELDS fields."); + return FALSE; + } + + if (t->DataFormat) { + t->DataFormat[n] = AllocString(it8, label); + } + + return TRUE; +} + + +cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample) +{ + cmsIT8* it8 = (cmsIT8*) h; + return SetDataFormat(it8, n, Sample); +} + +static +void AllocateDataSet(cmsIT8* it8) +{ + TABLE* t = GetTable(it8); + + if (t -> Data) return; // Already allocated + + t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); + t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); + + t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*)); + if (t->Data == NULL) { + + SynError(it8, "AllocateDataSet: Unable to allocate data array"); + } + +} + +static +char* GetData(cmsIT8* it8, int nSet, int nField) +{ + TABLE* t = GetTable(it8); + int nSamples = t -> nSamples; + int nPatches = t -> nPatches; + + if (nSet >= nPatches || nField >= nSamples) + return NULL; + + if (!t->Data) return NULL; + return t->Data [nSet * nSamples + nField]; +} + +static +cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val) +{ + TABLE* t = GetTable(it8); + + if (!t->Data) + AllocateDataSet(it8); + + if (!t->Data) return FALSE; + + if (nSet > t -> nPatches || nSet < 0) { + + return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches); + } + + if (nField > t ->nSamples || nField < 0) { + return SynError(it8, "Sample %d out of range, there are %d samples", nField, t ->nSamples); + + } + + t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val); + return TRUE; +} + + +// --------------------------------------------------------------- File I/O + + +// Writes a string to file +static +void WriteStr(SAVESTREAM* f, const char *str) +{ + cmsUInt32Number len; + + if (str == NULL) + str = " "; + + // Lenghth to write + len = (cmsUInt32Number) strlen(str); + f ->Used += len; + + + if (f ->stream) { // Should I write it to a file? + + if (fwrite(str, 1, len, f->stream) != len) { + cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser"); + return; + } + + } + else { // Or to a memory block? + + if (f ->Base) { // Am I just counting the bytes? + + if (f ->Used > f ->Max) { + + cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser"); + return; + } + + memmove(f ->Ptr, str, len); + f->Ptr += len; + } + + } +} + + +// Write formatted + +static +void Writef(SAVESTREAM* f, const char* frm, ...) +{ + char Buffer[4096]; + va_list args; + + va_start(args, frm); + vsnprintf(Buffer, 4095, frm, args); + Buffer[4095] = 0; + WriteStr(f, Buffer); + va_end(args); + +} + +// Writes full header +static +void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) +{ + KEYVALUE* p; + TABLE* t = GetTable(it8); + + + for (p = t->HeaderList; (p != NULL); p = p->Next) + { + if (*p ->Keyword == '#') { + + char* Pt; + + WriteStr(fp, "#\n# "); + for (Pt = p ->Value; *Pt; Pt++) { + + + Writef(fp, "%c", *Pt); + + if (*Pt == '\n') { + WriteStr(fp, "# "); + } + } + + WriteStr(fp, "\n#\n"); + continue; + } + + + if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) { + +#ifdef CMS_STRICT_CGATS + WriteStr(fp, "KEYWORD\t\""); + WriteStr(fp, p->Keyword); + WriteStr(fp, "\"\n"); +#endif + + AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED); + } + + WriteStr(fp, p->Keyword); + if (p->Value) { + + switch (p ->WriteAs) { + + case WRITE_UNCOOKED: + Writef(fp, "\t%s", p ->Value); + break; + + case WRITE_STRINGIFY: + Writef(fp, "\t\"%s\"", p->Value ); + break; + + case WRITE_HEXADECIMAL: + Writef(fp, "\t0x%X", atoi(p ->Value)); + break; + + case WRITE_BINARY: + Writef(fp, "\t0x%B", atoi(p ->Value)); + break; + + case WRITE_PAIR: + Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value); + break; + + default: SynError(it8, "Unknown write mode %d", p ->WriteAs); + return; + } + } + + WriteStr (fp, "\n"); + } + +} + + +// Writes the data format +static +void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) +{ + int i, nSamples; + TABLE* t = GetTable(it8); + + if (!t -> DataFormat) return; + + WriteStr(fp, "BEGIN_DATA_FORMAT\n"); + WriteStr(fp, " "); + nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); + + for (i = 0; i < nSamples; i++) { + + WriteStr(fp, t->DataFormat[i]); + WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t")); + } + + WriteStr (fp, "END_DATA_FORMAT\n"); +} + + +// Writes data array +static +void WriteData(SAVESTREAM* fp, cmsIT8* it8) +{ + int i, j; + TABLE* t = GetTable(it8); + + if (!t->Data) return; + + WriteStr (fp, "BEGIN_DATA\n"); + + t->nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); + + for (i = 0; i < t-> nPatches; i++) { + + WriteStr(fp, " "); + + for (j = 0; j < t->nSamples; j++) { + + char *ptr = t->Data[i*t->nSamples+j]; + + if (ptr == NULL) WriteStr(fp, "\"\""); + else { + // If value contains whitespace, enclose within quote + + if (strchr(ptr, ' ') != NULL) { + + WriteStr(fp, "\""); + WriteStr(fp, ptr); + WriteStr(fp, "\""); + } + else + WriteStr(fp, ptr); + } + + WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t")); + } + } + WriteStr (fp, "END_DATA\n"); +} + + + +// Saves whole file +cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) +{ + SAVESTREAM sd; + cmsUInt32Number i; + cmsIT8* it8 = (cmsIT8*) hIT8; + + memset(&sd, 0, sizeof(sd)); + + sd.stream = fopen(cFileName, "wt"); + if (!sd.stream) return FALSE; + + WriteStr(&sd, it8->SheetType); + WriteStr(&sd, "\n"); + for (i=0; i < it8 ->TablesCount; i++) { + + cmsIT8SetTable(hIT8, i); + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); + } + + if (fclose(sd.stream) != 0) return FALSE; + + return TRUE; +} + + +// Saves to memory +cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded) +{ + SAVESTREAM sd; + cmsUInt32Number i; + cmsIT8* it8 = (cmsIT8*) hIT8; + + memset(&sd, 0, sizeof(sd)); + + sd.stream = NULL; + sd.Base = (cmsUInt8Number*) MemPtr; + sd.Ptr = sd.Base; + + sd.Used = 0; + + if (sd.Base) + sd.Max = *BytesNeeded; // Write to memory? + else + sd.Max = 0; // Just counting the needed bytes + + WriteStr(&sd, it8->SheetType); + WriteStr(&sd, "\n"); + for (i=0; i < it8 ->TablesCount; i++) { + + cmsIT8SetTable(hIT8, i); + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); + } + + sd.Used++; // The \0 at the very end + + if (sd.Base) + sd.Ptr = 0; + + *BytesNeeded = sd.Used; + + return TRUE; +} + + +// -------------------------------------------------------------- Higer level parsing + +static +cmsBool DataFormatSection(cmsIT8* it8) +{ + int iField = 0; + TABLE* t = GetTable(it8); + + InSymbol(it8); // Eats "BEGIN_DATA_FORMAT" + CheckEOLN(it8); + + while (it8->sy != SEND_DATA_FORMAT && + it8->sy != SEOLN && + it8->sy != SEOF && + it8->sy != SSYNERROR) { + + if (it8->sy != SIDENT) { + + return SynError(it8, "Sample type expected"); + } + + if (!SetDataFormat(it8, iField, it8->id)) return FALSE; + iField++; + + InSymbol(it8); + SkipEOLN(it8); + } + + SkipEOLN(it8); + Skip(it8, SEND_DATA_FORMAT); + SkipEOLN(it8); + + if (iField != t ->nSamples) { + SynError(it8, "Count mismatch. NUMBER_OF_FIELDS was %d, found %d\n", t ->nSamples, iField); + + + } + + return TRUE; +} + + + +static +cmsBool DataSection (cmsIT8* it8) +{ + int iField = 0; + int iSet = 0; + char Buffer[256]; + TABLE* t = GetTable(it8); + + InSymbol(it8); // Eats "BEGIN_DATA" + CheckEOLN(it8); + + if (!t->Data) + AllocateDataSet(it8); + + while (it8->sy != SEND_DATA && it8->sy != SEOF) + { + if (iField >= t -> nSamples) { + iField = 0; + iSet++; + + } + + if (it8->sy != SEND_DATA && it8->sy != SEOF) { + + if (!GetVal(it8, Buffer, 255, "Sample data expected")) + return FALSE; + + if (!SetData(it8, iSet, iField, Buffer)) + return FALSE; + + iField++; + + InSymbol(it8); + SkipEOLN(it8); + } + } + + SkipEOLN(it8); + Skip(it8, SEND_DATA); + SkipEOLN(it8); + + // Check for data completion. + + if ((iSet+1) != t -> nPatches) + return SynError(it8, "Count mismatch. NUMBER_OF_SETS was %d, found %d\n", t ->nPatches, iSet+1); + + return TRUE; +} + + + + +static +cmsBool HeaderSection(cmsIT8* it8) +{ + char VarName[MAXID]; + char Buffer[MAXSTR]; + KEYVALUE* Key; + + while (it8->sy != SEOF && + it8->sy != SSYNERROR && + it8->sy != SBEGIN_DATA_FORMAT && + it8->sy != SBEGIN_DATA) { + + + switch (it8 -> sy) { + + case SKEYWORD: + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; + InSymbol(it8); + break; + + + case SDATA_FORMAT_ID: + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableSampleID(it8, Buffer)) return FALSE; + InSymbol(it8); + break; + + + case SIDENT: + strncpy(VarName, it8->id, MAXID-1); + VarName[MAXID-1] = 0; + + if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) { + +#ifdef CMS_STRICT_CGATS + return SynError(it8, "Undefined keyword '%s'", VarName); +#else + Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); + if (Key == NULL) return FALSE; +#endif + } + + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE; + + if(Key->WriteAs != WRITE_PAIR) { + AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, + (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); + } + else { + const char *Subkey; + char *Nextkey; + if (it8->sy != SSTRING) + return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName); + + // chop the string as a list of "subkey, value" pairs, using ';' as a separator + for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) + { + char *Value, *temp; + + // identify token pair boundary + Nextkey = (char*) strchr(Subkey, ';'); + if(Nextkey) + *Nextkey++ = '\0'; + + // for each pair, split the subkey and the value + Value = (char*) strrchr(Subkey, ','); + if(Value == NULL) + return SynError(it8, "Invalid value for property '%s'.", VarName); + + // gobble the spaces before the coma, and the coma itself + temp = Value++; + do *temp-- = '\0'; while(temp >= Subkey && *temp == ' '); + + // gobble any space at the right + temp = Value + strlen(Value) - 1; + while(*temp == ' ') *temp-- = '\0'; + + // trim the strings from the left + Subkey += strspn(Subkey, " "); + Value += strspn(Value, " "); + + if(Subkey[0] == 0 || Value[0] == 0) + return SynError(it8, "Invalid value for property '%s'.", VarName); + AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); + } + } + + InSymbol(it8); + break; + + + case SEOLN: break; + + default: + return SynError(it8, "expected keyword or identifier"); + } + + SkipEOLN(it8); + } + + return TRUE; + +} + + +static +cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) +{ + char* SheetTypePtr = it8 ->SheetType; + + if (nosheet == 0) { + + // First line is a very special case. + + while (isseparator(it8->ch)) + NextCh(it8); + + while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) { + + *SheetTypePtr++= (char) it8 ->ch; + NextCh(it8); + } + } + + *SheetTypePtr = 0; + InSymbol(it8); + + SkipEOLN(it8); + + while (it8-> sy != SEOF && + it8-> sy != SSYNERROR) { + + switch (it8 -> sy) { + + case SBEGIN_DATA_FORMAT: + if (!DataFormatSection(it8)) return FALSE; + break; + + case SBEGIN_DATA: + + if (!DataSection(it8)) return FALSE; + + if (it8 -> sy != SEOF) { + + AllocTable(it8); + it8 ->nTable = it8 ->TablesCount - 1; + } + break; + + case SEOLN: + SkipEOLN(it8); + break; + + default: + if (!HeaderSection(it8)) return FALSE; + } + + } + + return (it8 -> sy != SSYNERROR); +} + + + +// Init usefull pointers + +static +void CookPointers(cmsIT8* it8) +{ + int idField, i; + char* Fld; + cmsUInt32Number j; + cmsUInt32Number nOldTable = it8 ->nTable; + + for (j=0; j < it8 ->TablesCount; j++) { + + TABLE* t = it8 ->Tab + j; + + t -> SampleID = 0; + it8 ->nTable = j; + + for (idField = 0; idField < t -> nSamples; idField++) + { + if (t ->DataFormat == NULL){ + SynError(it8, "Undefined DATA_FORMAT"); + return; + } + + Fld = t->DataFormat[idField]; + if (!Fld) continue; + + + if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { + + t -> SampleID = idField; + + for (i=0; i < t -> nPatches; i++) { + + char *Data = GetData(it8, i, idField); + if (Data) { + char Buffer[256]; + + strncpy(Buffer, Data, 255); + Buffer[255] = 0; + + if (strlen(Buffer) <= strlen(Data)) + strcpy(Data, Buffer); + else + SetData(it8, i, idField, Buffer); + + } + } + + } + + // "LABEL" is an extension. It keeps references to forward tables + + if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) { + + // Search for table references... + for (i=0; i < t -> nPatches; i++) { + + char *Label = GetData(it8, i, idField); + + if (Label) { + + cmsUInt32Number k; + + // This is the label, search for a table containing + // this property + + for (k=0; k < it8 ->TablesCount; k++) { + + TABLE* Table = it8 ->Tab + k; + KEYVALUE* p; + + if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { + + // Available, keep type and table + char Buffer[256]; + + char *Type = p ->Value; + int nTable = k; + + snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); + + SetData(it8, i, idField, Buffer); + } + } + + + } + + } + + + } + + } + } + + it8 ->nTable = nOldTable; +} + +// Try to infere if the file is a CGATS/IT8 file at all. Read first line +// that should be something like some printable characters plus a \n + +static +int IsMyBlock(cmsUInt8Number* Buffer, int n) +{ + int cols = 1, space = 0, quot = 0; + int i; + + if (n < 10) return FALSE; // Too small + + if (n > 132) + n = 132; + + for (i = 1; i < n; i++) { + + switch(Buffer[i]) + { + case '\n': + case '\r': + return quot == 1 || cols > 2 ? 0 : cols; + case '\t': + case ' ': + if(!quot && !space) + space = 1; + break; + case '\"': + quot = !quot; + break; + default: + if (Buffer[i] < 32) return 0; + if (Buffer[i] > 127) return 0; + cols += space; + space = 0; + break; + } + } + + return FALSE; + +} + + +static +cmsBool IsMyFile(const char* FileName) +{ + FILE *fp; + cmsUInt32Number Size; + cmsUInt8Number Ptr[133]; + + fp = fopen(FileName, "rt"); + if (!fp) { + cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName); + return FALSE; + } + + Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp); + + if (fclose(fp) != 0) + return FALSE; + + Ptr[Size] = '\0'; + + return IsMyBlock(Ptr, Size); +} + +// ---------------------------------------------------------- Exported routines + + +cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len) +{ + cmsHANDLE hIT8; + cmsIT8* it8; + int type; + + _cmsAssert(Ptr != NULL); + _cmsAssert(len != 0); + + type = IsMyBlock((cmsUInt8Number*)Ptr, len); + if (type == 0) return NULL; + + hIT8 = cmsIT8Alloc(ContextID); + if (!hIT8) return NULL; + + it8 = (cmsIT8*) hIT8; + it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1); + + strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); + it8 ->MemoryBlock[len] = 0; + + strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1); + it8-> Source = it8 -> MemoryBlock; + + if (!ParseIT8(it8, type-1)) { + + cmsIT8Free(hIT8); + return FALSE; + } + + CookPointers(it8); + it8 ->nTable = 0; + + _cmsFree(ContextID, it8->MemoryBlock); + it8 -> MemoryBlock = NULL; + + return hIT8; + + +} + + +cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName) +{ + + cmsHANDLE hIT8; + cmsIT8* it8; + int type; + + _cmsAssert(cFileName != NULL); + + type = IsMyFile(cFileName); + if (type == 0) return NULL; + + hIT8 = cmsIT8Alloc(ContextID); + it8 = (cmsIT8*) hIT8; + if (!hIT8) return NULL; + + + it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); + + if (!it8 ->FileStack[0]->Stream) { + cmsIT8Free(hIT8); + return NULL; + } + + + strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1); + it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0; + + if (!ParseIT8(it8, type-1)) { + + fclose(it8 ->FileStack[0]->Stream); + cmsIT8Free(hIT8); + return NULL; + } + + CookPointers(it8); + it8 ->nTable = 0; + + if (fclose(it8 ->FileStack[0]->Stream)!= 0) { + cmsIT8Free(hIT8); + return NULL; + } + + return hIT8; + +} + +int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + + if (SampleNames) + *SampleNames = t -> DataFormat; + return t -> nSamples; +} + + +cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE* p; + cmsUInt32Number n; + char **Props; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + + // Pass#1 - count properties + + n = 0; + for (p = t -> HeaderList; p != NULL; p = p->Next) { + n++; + } + + + Props = (char **) AllocChunk(it8, sizeof(char *) * n); + + // Pass#2 - Fill pointers + n = 0; + for (p = t -> HeaderList; p != NULL; p = p->Next) { + Props[n++] = p -> Keyword; + } + + *PropertyNames = Props; + return n; +} + +cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE *p, *tmp; + cmsUInt32Number n; + const char **Props; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + + t = GetTable(it8); + + if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { + *SubpropertyNames = 0; + return 0; + } + + // Pass#1 - count properties + + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + n++; + } + + + Props = (const char **) AllocChunk(it8, sizeof(char *) * n); + + // Pass#2 - Fill pointers + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + Props[n++] = p ->Subkey; + } + + *SubpropertyNames = Props; + return n; +} + +static +int LocatePatch(cmsIT8* it8, const char* cPatch) +{ + int i; + const char *data; + TABLE* t = GetTable(it8); + + for (i=0; i < t-> nPatches; i++) { + + data = GetData(it8, i, t->SampleID); + + if (data != NULL) { + + if (cmsstrcasecmp(data, cPatch) == 0) + return i; + } + } + + // SynError(it8, "Couldn't find patch '%s'\n", cPatch); + return -1; +} + + +static +int LocateEmptyPatch(cmsIT8* it8) +{ + int i; + const char *data; + TABLE* t = GetTable(it8); + + for (i=0; i < t-> nPatches; i++) { + + data = GetData(it8, i, t->SampleID); + + if (data == NULL) + return i; + + } + + return -1; +} + +static +int LocateSample(cmsIT8* it8, const char* cSample) +{ + int i; + const char *fld; + TABLE* t = GetTable(it8); + + for (i=0; i < t->nSamples; i++) { + + fld = GetDataFormat(it8, i); + if (cmsstrcasecmp(fld, cSample) == 0) + return i; + } + + return -1; + +} + + +int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return LocateSample(it8, cSample); +} + + + +const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return GetData(it8, row, col); +} + + +cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col) +{ + const char* Buffer; + + Buffer = cmsIT8GetDataRowCol(hIT8, row, col); + + if (Buffer) { + + return atof(Buffer); + + } else + return 0; + +} + + +cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return SetData(it8, row, col, Val); +} + + +cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buff[256]; + + _cmsAssert(hIT8 != NULL); + + sprintf(Buff, it8->DoubleFormatter, Val); + + return SetData(it8, row, col, Buff); +} + + + +const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + int iField, iSet; + + _cmsAssert(hIT8 != NULL); + + iField = LocateSample(it8, cSample); + if (iField < 0) { + return NULL; + } + + iSet = LocatePatch(it8, cPatch); + if (iSet < 0) { + return NULL; + } + + return GetData(it8, iSet, iField); +} + + +cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* cSample) +{ + const char* Buffer; + + Buffer = cmsIT8GetData(it8, cPatch, cSample); + + if (Buffer) { + + return atof(Buffer); + + } else { + + return 0; + } +} + + + +cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + int iField, iSet; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + + iField = LocateSample(it8, cSample); + + if (iField < 0) + return FALSE; + + if (t-> nPatches == 0) { + + AllocateDataFormat(it8); + AllocateDataSet(it8); + CookPointers(it8); + } + + if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) { + + iSet = LocateEmptyPatch(it8); + if (iSet < 0) { + return SynError(it8, "Couldn't add more patches '%s'\n", cPatch); + } + + iField = t -> SampleID; + } + else { + iSet = LocatePatch(it8, cPatch); + if (iSet < 0) { + return FALSE; + } + } + + return SetData(it8, iSet, iField, Val); +} + + +cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, + const char* cSample, + cmsFloat64Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buff[256]; + + _cmsAssert(hIT8 != NULL); + + snprintf(Buff, 255, it8->DoubleFormatter, Val); + return cmsIT8SetData(hIT8, cPatch, cSample, Buff); +} + +// Buffer should get MAXSTR at least + +const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t; + char* Data; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + Data = GetData(it8, nPatch, t->SampleID); + + if (!Data) return NULL; + if (!buffer) return Data; + + strncpy(buffer, Data, MAXSTR-1); + buffer[MAXSTR-1] = 0; + return buffer; +} + +int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch) +{ + _cmsAssert(hIT8 != NULL); + + return LocatePatch((cmsIT8*)hIT8, cPatch); +} + +cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return it8 ->TablesCount; +} + +// This handles the "LABEL" extension. +// Label, nTable, Type + +int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType) +{ + const char* cLabelFld; + char Type[256], Label[256]; + int nTable; + + _cmsAssert(hIT8 != NULL); + + if (cField != NULL && *cField == 0) + cField = "LABEL"; + + if (cField == NULL) + cField = "LABEL"; + + cLabelFld = cmsIT8GetData(hIT8, cSet, cField); + if (!cLabelFld) return -1; + + if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3) + return -1; + + if (ExpectedType != NULL && *ExpectedType == 0) + ExpectedType = NULL; + + if (ExpectedType) { + + if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1; + } + + return cmsIT8SetTable(hIT8, nTable); +} + + +cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + int pos; + + _cmsAssert(hIT8 != NULL); + + pos = LocateSample(it8, cSample); + if(pos == -1) + return FALSE; + + it8->Tab[it8->nTable].SampleID = pos; + return TRUE; +} + + +void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + if (Formatter == NULL) + strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); + else + strcpy(it8->DoubleFormatter, Formatter); +} + diff --git a/thirdparty/liblcms2/src/cmscnvrt.c b/thirdparty/liblcms2/src/cmscnvrt.c new file mode 100644 index 00000000..8dadc875 --- /dev/null +++ b/thirdparty/liblcms2/src/cmscnvrt.c @@ -0,0 +1,1039 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point +// compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS +// after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1) +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + +// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. +// Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric +static +cmsPipeline* DefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + +// This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile +// to do the trick (no devicelinks allowed at that position) +static +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + +// This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile +// to do the trick (no devicelinks allowed at that position) +static +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + + +// This is a structure holding implementations for all supported intents. +typedef struct _cms_intents_list { + + cmsUInt32Number Intent; + char Description[256]; + cmsIntentFn Link; + struct _cms_intents_list* Next; + +} cmsIntentsList; + + +// Built-in intents +static cmsIntentsList DefaultIntents[] = { + + { INTENT_PERCEPTUAL, "Perceptual", DefaultICCintents, &DefaultIntents[1] }, + { INTENT_RELATIVE_COLORIMETRIC, "Relative colorimetric", DefaultICCintents, &DefaultIntents[2] }, + { INTENT_SATURATION, "Saturation", DefaultICCintents, &DefaultIntents[3] }, + { INTENT_ABSOLUTE_COLORIMETRIC, "Absolute colorimetric", DefaultICCintents, &DefaultIntents[4] }, + { INTENT_PRESERVE_K_ONLY_PERCEPTUAL, "Perceptual preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[5] }, + { INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC, "Relative colorimetric preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[6] }, + { INTENT_PRESERVE_K_ONLY_SATURATION, "Saturation preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[7] }, + { INTENT_PRESERVE_K_PLANE_PERCEPTUAL, "Perceptual preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[8] }, + { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] }, + { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } +}; + + +// A pointer to the begining of the list +static cmsIntentsList *Intents = DefaultIntents; + +// Search the list for a suitable intent. Returns NULL if not found +static +cmsIntentsList* SearchIntent(cmsUInt32Number Intent) +{ + cmsIntentsList* pt; + + for (pt = Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + return NULL; +} + +// Black point compensation. Implemented as a linear scaling in XYZ. Black points +// should come relative to the white point. Fills an matrix/offset element m +// which is organized as a 4x4 matrix. +static +void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, + const cmsCIEXYZ* BlackPointOut, + cmsMAT3* m, cmsVEC3* off) +{ + cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz; + + // Now we need to compute a matrix plus an offset m and of such of + // [m]*bpin + off = bpout + // [m]*D50 + off = D50 + // + // This is a linear scaling in the form ax+b, where + // a = (bpout - D50) / (bpin - D50) + // b = - D50* (bpout - bpin) / (bpin - D50) + + tx = BlackPointIn->X - cmsD50_XYZ()->X; + ty = BlackPointIn->Y - cmsD50_XYZ()->Y; + tz = BlackPointIn->Z - cmsD50_XYZ()->Z; + + ax = (BlackPointOut->X - cmsD50_XYZ()->X) / tx; + ay = (BlackPointOut->Y - cmsD50_XYZ()->Y) / ty; + az = (BlackPointOut->Z - cmsD50_XYZ()->Z) / tz; + + bx = - cmsD50_XYZ()-> X * (BlackPointOut->X - BlackPointIn->X) / tx; + by = - cmsD50_XYZ()-> Y * (BlackPointOut->Y - BlackPointIn->Y) / ty; + bz = - cmsD50_XYZ()-> Z * (BlackPointOut->Z - BlackPointIn->Z) / tz; + + _cmsVEC3init(&m ->v[0], ax, 0, 0); + _cmsVEC3init(&m ->v[1], 0, ay, 0); + _cmsVEC3init(&m ->v[2], 0, 0, az); + _cmsVEC3init(off, bx, by, bz); + +} + + +// Approximate a blackbody illuminant based on CHAD information +static +cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) +{ + // Convert D50 across CHAD to get the absolute white point + cmsVEC3 d, s; + cmsCIEXYZ Dest; + cmsCIExyY DestChromaticity; + cmsFloat64Number TempK; + + s.n[VX] = cmsD50_XYZ() -> X; + s.n[VY] = cmsD50_XYZ() -> Y; + s.n[VZ] = cmsD50_XYZ() -> Z; + + _cmsMAT3eval(&d, Chad, &s); + + Dest.X = d.n[VX]; + Dest.Y = d.n[VY]; + Dest.Z = d.n[VZ]; + + cmsXYZ2xyY(&DestChromaticity, &Dest); + + if (!cmsTempFromWhitePoint(&TempK, &DestChromaticity)) + return -1.0; + + return TempK; +} + +// Compute a CHAD based on a given temperature +static +void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) +{ + cmsCIEXYZ White; + cmsCIExyY ChromaticityOfWhite; + + cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); + cmsxyY2XYZ(&White, &ChromaticityOfWhite); + _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White); + +} + +// Join scalings to obtain relative input to absolute and then to relative output. +// Result is stored in a 3x3 matrix +static +cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, + const cmsCIEXYZ* WhitePointIn, + const cmsMAT3* ChromaticAdaptationMatrixIn, + const cmsCIEXYZ* WhitePointOut, + const cmsMAT3* ChromaticAdaptationMatrixOut, + cmsMAT3* m) +{ + cmsMAT3 Scale, m1, m2, m3; + + // Adaptation state + if (AdaptationState == 1.0) { + + // Observer is fully adapted. Keep chromatic adaptation. + // That is the standard V4 behaviour + _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); + _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); + _cmsVEC3init(&m->v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); + + } + else { + + // Incomplete adaptation. This is an advanced feature. + _cmsVEC3init(&Scale.v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); + _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); + _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); + + m1 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; + _cmsMAT3per(&m3, &m2, &Scale); + + // m3 holds CHAD from input white to D50 times abs. col. scaling + if (AdaptationState == 0.0) { + + // Observer is not adapted, undo the chromatic adaptation + _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut); + + } else { + + cmsMAT3 MixedCHAD; + cmsFloat64Number TempSrc, TempDest, Temp; + + TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); // K for source white + TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white + + if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong + + if (_cmsMAT3isIdentity(&Scale) && fabs(TempSrc - TempDest) < 0.01) { + + _cmsMAT3identity(m); + return TRUE; + } + + Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest; + + // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD + Temp2CHAD(&MixedCHAD, Temp); + + _cmsMAT3per(m, &m3, &MixedCHAD); + } + + } + return TRUE; + +} + +// Just to see if m matrix should be applied +static +cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) +{ + cmsFloat64Number diff = 0; + cmsMAT3 Ident; + int i; + + if (m == NULL && off == NULL) return TRUE; // NULL is allowed as an empty layer + if (m == NULL && off != NULL) return FALSE; // This is an internal error + + _cmsMAT3identity(&Ident); + + for (i=0; i < 3*3; i++) + diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]); + + for (i=0; i < 3; i++) + diff += fabs(((cmsFloat64Number*)off)[i]); + + + return (diff < 0.002); +} + + +// Compute the conversion layer +static +cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], + cmsUInt32Number Intent, + cmsBool BPC, + cmsFloat64Number AdaptationState, + cmsMAT3* m, cmsVEC3* off) +{ + + int k; + + // m and off are set to identity and this is detected latter on + _cmsMAT3identity(m); + _cmsVEC3init(off, 0, 0, 0); + + // If intent is abs. colorimetric, + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) { + + cmsCIEXYZ WhitePointIn, WhitePointOut; + cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; + + _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); + _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); + + _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); + _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); + + if (!ComputeAbsoluteIntent(AdaptationState, + &WhitePointIn, &ChromaticAdaptationMatrixIn, + &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE; + + } + else { + // Rest of intents may apply BPC. + + if (BPC) { + + cmsCIEXYZ BlackPointIn, BlackPointOut; + + cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0); + cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); + + // If black points are equal, then do nothing + if (BlackPointIn.X != BlackPointOut.X || + BlackPointIn.Y != BlackPointOut.Y || + BlackPointIn.Z != BlackPointOut.Z) + ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off); + } + } + + // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0, + // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so + // we have first to convert from encoded to XYZ and then convert back to encoded. + // y = Mx + Off + // x = x'c + // y = M x'c + Off + // y = y'c; y' = y / c + // y' = (Mx'c + Off) /c = Mx' + (Off / c) + + for (k=0; k < 3; k++) { + off ->n[k] /= MAX_ENCODEABLE_XYZ; + } + + return TRUE; +} + + +// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space +static +cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off) +{ + cmsFloat64Number* m_as_dbl = (cmsFloat64Number*) m; + cmsFloat64Number* off_as_dbl = (cmsFloat64Number*) off; + + // Handle PCS mismatches. A specialized stage is added to the LUT in such case + switch (InPCS) { + + case cmsSigXYZData: // Input profile operates in XYZ + + switch (OutPCS) { + + case cmsSigXYZData: // XYZ -> XYZ + if (!IsEmptyLayer(m, off)) + cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); + break; + + case cmsSigLabData: // XYZ -> Lab + if (!IsEmptyLayer(m, off)) + cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); + cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); + break; + + default: + return FALSE; // Colorspace mismatch + } + break; + + + case cmsSigLabData: // Input profile operates in Lab + + switch (OutPCS) { + + case cmsSigXYZData: // Lab -> XYZ + + cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); + if (!IsEmptyLayer(m, off)) + cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); + break; + + case cmsSigLabData: // Lab -> Lab + + if (!IsEmptyLayer(m, off)) { + cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); + cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); + cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); + } + break; + + default: + return FALSE; // Mismatch + } + break; + + + // On colorspaces other than PCS, check for same space + default: + if (InPCS != OutPCS) return FALSE; + break; + } + + return TRUE; +} + + +// Is a given space compatible with another? +static +cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature b) +{ + // If they are same, they are compatible. + if (a == b) return TRUE; + + // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other. + if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE; + if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE; + + return FALSE; +} + + +// Default handler for ICC-style intents +static +cmsPipeline* DefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsPipeline* Lut, *Result; + cmsHPROFILE hProfile; + cmsMAT3 m; + cmsVEC3 off; + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; + cmsProfileClassSignature ClassSig; + cmsUInt32Number i, Intent; + + // For safety + if (nProfiles == 0) return NULL; + + // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined' + Result = cmsPipelineAlloc(ContextID, 0, 0); + if (Result == NULL) return NULL; + + CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); + + for (i=0; i < nProfiles; i++) { + + cmsBool lIsDeviceLink, lIsInput; + + hProfile = hProfiles[i]; + ClassSig = cmsGetDeviceClass(hProfile); + lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass ); + + // First profile is used as input unless devicelink or abstract + if ((i == 0) && !lIsDeviceLink) { + lIsInput = TRUE; + } + else { + // Else use profile in the input direction if current space is not PCS + lIsInput = (CurrentColorSpace != cmsSigXYZData) && + (CurrentColorSpace != cmsSigLabData); + } + + Intent = TheIntents[i]; + + if (lIsInput || lIsDeviceLink) { + + ColorSpaceIn = cmsGetColorSpace(hProfile); + ColorSpaceOut = cmsGetPCS(hProfile); + } + else { + + ColorSpaceIn = cmsGetPCS(hProfile); + ColorSpaceOut = cmsGetColorSpace(hProfile); + } + + if (!ColorSpaceIsCompatible(ColorSpaceIn, CurrentColorSpace)) { + + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "ColorSpace mismatch"); + goto Error; + } + + // If devicelink is found, then no custom intent is allowed and we can + // read the LUT to be applied. Settings don't apply here. + if (lIsDeviceLink) { + + // Get the involved LUT from the profile + Lut = _cmsReadDevicelinkLUT(hProfile, Intent); + if (Lut == NULL) goto Error; + + // What about abstract profiles? + if (ClassSig == cmsSigAbstractClass && i > 0) { + if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error; + } + else { + _cmsMAT3identity(&m); + _cmsVEC3init(&off, 0, 0, 0); + } + + + if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; + + } + else { + + if (lIsInput) { + // Input direction means non-pcs connection, so proceed like devicelinks + Lut = _cmsReadInputLUT(hProfile, Intent); + if (Lut == NULL) goto Error; + } + else { + + // Output direction means PCS connection. Intent may apply here + Lut = _cmsReadOutputLUT(hProfile, Intent); + if (Lut == NULL) goto Error; + + + if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error; + if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; + + } + } + + // Concatenate to the output LUT + cmsPipelineCat(Result, Lut); + cmsPipelineFree(Lut); + + // Update current space + CurrentColorSpace = ColorSpaceOut; + } + + return Result; + +Error: + + if (Result != NULL) cmsPipelineFree(Result); + return NULL; + + cmsUNUSED_PARAMETER(dwFlags); +} + + +// Wrapper for DLL calling convention +cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + return DefaultICCintents(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); +} + +// Black preserving intents --------------------------------------------------------------------------------------------- + +// Translate black-preserving intents to ICC ones +static +int TranslateNonICCIntents(int Intent) +{ + switch (Intent) { + case INTENT_PRESERVE_K_ONLY_PERCEPTUAL: + case INTENT_PRESERVE_K_PLANE_PERCEPTUAL: + return INTENT_PERCEPTUAL; + + case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC: + case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC: + return INTENT_RELATIVE_COLORIMETRIC; + + case INTENT_PRESERVE_K_ONLY_SATURATION: + case INTENT_PRESERVE_K_PLANE_SATURATION: + return INTENT_SATURATION; + + default: return Intent; + } +} + +// Sampler for Black-only preserving CMYK->CMYK transforms + +typedef struct { + cmsPipeline* cmyk2cmyk; // The original transform + cmsToneCurve* KTone; // Black-to-black tone curve + +} GrayOnlyParams; + + +// Preserve black only if that is the only ink used +static +int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + GrayOnlyParams* bp = (GrayOnlyParams*) Cargo; + + // If going across black only, keep black only + if (In[0] == 0 && In[1] == 0 && In[2] == 0) { + + // TAC does not apply because it is black ink! + Out[0] = Out[1] = Out[2] = 0; + Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]); + return TRUE; + } + + // Keep normal transform for other colors + bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data); + return TRUE; +} + +// This is the entry for black-preserving K-only intents, which are non-ICC +static +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + GrayOnlyParams bp; + cmsPipeline* Result; + cmsUInt32Number ICCIntents[256]; + cmsStage* CLUT; + cmsUInt32Number i, nGridPoints; + + + // Sanity check + if (nProfiles < 1 || nProfiles > 255) return NULL; + + // Translate black-preserving intents to ICC ones + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + + // Check for non-cmyk profiles + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); + + memset(&bp, 0, sizeof(bp)); + + // Allocate an empty LUT for holding the result + Result = cmsPipelineAlloc(ContextID, 4, 4); + if (Result == NULL) return NULL; + + // Create a LUT holding normal ICC transform + bp.cmyk2cmyk = DefaultICCintents(ContextID, + nProfiles, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + + if (bp.cmyk2cmyk == NULL) goto Error; + + // Now, compute the tone curve + bp.KTone = _cmsBuildKToneCurve(ContextID, + 4096, + nProfiles, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + + if (bp.KTone == NULL) goto Error; + + + // How many gridpoints are we going to use? + nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); + + // Create the CLUT. 16 bits + CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); + if (CLUT == NULL) goto Error; + + // This is the one and only MPE in this LUT + cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + + // Sample it. We cannot afford pre/post linearization this time. + if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) + goto Error; + + // Get rid of xform and tone curve + cmsPipelineFree(bp.cmyk2cmyk); + cmsFreeToneCurve(bp.KTone); + + return Result; + +Error: + + if (bp.cmyk2cmyk != NULL) cmsPipelineFree(bp.cmyk2cmyk); + if (bp.KTone != NULL) cmsFreeToneCurve(bp.KTone); + if (Result != NULL) cmsPipelineFree(Result); + return NULL; + +} + +// K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------ + +typedef struct { + + cmsPipeline* cmyk2cmyk; // The original transform + cmsHTRANSFORM hProofOutput; // Output CMYK to Lab (last profile) + cmsHTRANSFORM cmyk2Lab; // The input chain + cmsToneCurve* KTone; // Black-to-black tone curve + cmsPipeline* LabK2cmyk; // The output profile + cmsFloat64Number MaxError; + + cmsHTRANSFORM hRoundTrip; + cmsFloat64Number MaxTAC; + + +} PreserveKPlaneParams; + + +// The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision +static +int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + int i; + cmsFloat32Number Inf[4], Outf[4]; + cmsFloat32Number LabK[4]; + cmsFloat64Number SumCMY, SumCMYK, Error, Ratio; + cmsCIELab ColorimetricLab, BlackPreservingLab; + PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo; + + // Convert from 16 bits to floating point + for (i=0; i < 4; i++) + Inf[i] = (cmsFloat32Number) (In[i] / 65535.0); + + // Get the K across Tone curve + LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]); + + // If going across black only, keep black only + if (In[0] == 0 && In[1] == 0 && In[2] == 0) { + + Out[0] = Out[1] = Out[2] = 0; + Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0); + return TRUE; + } + + // Try the original transform, + cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); + + // Store a copy of the floating point result into 16-bit + for (i=0; i < 4; i++) + Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0); + + // Maybe K is already ok (mostly on K=0) + if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) { + return TRUE; + } + + // K differ, mesure and keep Lab measurement for further usage + // this is done in relative colorimetric intent + cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); + + // Is not black only and the transform doesn't keep black. + // Obtain the Lab of output CMYK. After that we have Lab + K + cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1); + + // Obtain the corresponding CMY using reverse interpolation + // (K is fixed in LabK[3]) + if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) { + + // Cannot find a suitable value, so use colorimetric xform + // which is already stored in Out[] + return TRUE; + } + + // Make sure to pass thru K (which now is fixed) + Outf[3] = LabK[3]; + + // Apply TAC if needed + SumCMY = Outf[0] + Outf[1] + Outf[2]; + SumCMYK = SumCMY + Outf[3]; + + if (SumCMYK > bp ->MaxTAC) { + + Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY); + if (Ratio < 0) + Ratio = 0; + } + else + Ratio = 1.0; + + Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C + Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M + Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y + Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0); + + // Estimate the error (this goes 16 bits to Lab DBL) + cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); + Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); + if (Error > bp -> MaxError) + bp->MaxError = Error; + + return TRUE; +} + +// This is the entry for black-plane preserving, which are non-ICC +static +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + PreserveKPlaneParams bp; + cmsPipeline* Result = NULL; + cmsUInt32Number ICCIntents[256]; + cmsStage* CLUT; + cmsUInt32Number i, nGridPoints; + cmsHPROFILE hLab; + + // Sanity check + if (nProfiles < 1 || nProfiles > 255) return NULL; + + // Translate black-preserving intents to ICC ones + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + + // Check for non-cmyk profiles + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); + + // Allocate an empty LUT for holding the result + Result = cmsPipelineAlloc(ContextID, 4, 4); + if (Result == NULL) return NULL; + + + memset(&bp, 0, sizeof(bp)); + + // We need the input LUT of the last profile, assuming this one is responsible of + // black generation. This LUT will be seached in inverse order. + bp.LabK2cmyk = _cmsReadInputLUT(hProfiles[nProfiles-1], INTENT_RELATIVE_COLORIMETRIC); + if (bp.LabK2cmyk == NULL) goto Cleanup; + + // Get total area coverage (in 0..1 domain) + bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0; + + // Create a LUT holding normal ICC transform + bp.cmyk2cmyk = DefaultICCintents(ContextID, + nProfiles, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + + // Now the tone curve + bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + + + // To measure the output, Last profile to Lab + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], + CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + + // Same as anterior, but lab in the 0..1 range + bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], + FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, + FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + cmsCloseProfile(hLab); + + // Error estimation (for debug only) + bp.MaxError = 0; + + // How many gridpoints are we going to use? + nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); + + + CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); + if (CLUT == NULL) goto Cleanup; + + cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + + cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); + +Cleanup: + + if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk); + if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); + if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput); + + if (bp.KTone) cmsFreeToneCurve(bp.KTone); + if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk); + + return Result; +} + +// Link routines ------------------------------------------------------------------------------------------------------ + +// Chain several profiles into a single LUT. It just checks the parameters and then calls the handler +// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the +// rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable. +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsIntentsList* Intent; + + // Make sure a reasonable number of profiles is provided + if (nProfiles <= 0 || nProfiles > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't link '%d' profiles", nProfiles); + return NULL; + } + + for (i=0; i < nProfiles; i++) { + + // Check if black point is really needed or allowed. Note that + // following Adobe's document: + // BPC does not apply to devicelink profiles, nor to abs colorimetric, + // and applies always on V4 perceptual and saturation. + + if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC) + BPC[i] = FALSE; + + if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) { + + // Force BPC for V4 profiles in perceptual and saturation + if (cmsGetProfileVersion(hProfiles[i]) >= 4.0) + BPC[i] = TRUE; + } + } + + // Search for a handler. The first intent in the chain defines the handler. That would + // prevent using multiple custom intents in a multiintent chain, but the behaviour of + // this case would present some issues if the custom intent tries to do things like + // preserve primaries. This solution is not perfect, but works well on most cases. + + Intent = SearchIntent(TheIntents[0]); + if (Intent == NULL) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); + return NULL; + } + + // Call the handler + return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); +} + +// ------------------------------------------------------------------------------------------------- + +// Get information about available intents. nMax is the maximum space for the supplied "Codes" +// and "Descriptions" the function returns the total number of intents, which may be greater +// than nMax, although the matrices are not populated beyond this level. +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + cmsIntentsList* pt; + cmsUInt32Number nIntents; + + for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } + + return nIntents; +} + +// The plug-in registration. User can add new intents or override default routines +cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data) +{ + cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; + cmsIntentsList* fl; + + // Do we have to reset the intents? + if (Data == NULL) { + + Intents = DefaultIntents; + return TRUE; + } + + fl = SearchIntent(Plugin ->Intent); + + if (fl == NULL) { + fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; + } + + fl ->Intent = Plugin ->Intent; + strncpy(fl ->Description, Plugin ->Description, 255); + fl ->Description[255] = 0; + + fl ->Link = Plugin ->Link; + + fl ->Next = Intents; + Intents = fl; + + return TRUE; +} + diff --git a/thirdparty/liblcms2/src/cmserr.c b/thirdparty/liblcms2/src/cmserr.c new file mode 100644 index 00000000..55f03580 --- /dev/null +++ b/thirdparty/liblcms2/src/cmserr.c @@ -0,0 +1,428 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- + +#include "lcms2_internal.h" + +// I am so tired about incompatibilities on those functions that here are some replacements +// that hopefully would be fully portable. + +// compare two strings ignoring case +int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) +{ + register const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (toupper(*us1) == toupper(*us2++)) + if (*us1++ == '\0') + return (0); + return (toupper(*us1) - toupper(*--us2)); +} + +// long int because C99 specifies ftell in such way (7.19.9.2) +long int CMSEXPORT cmsfilelength(FILE* f) +{ + long int p , n; + + p = ftell(f); // register current file position + + if (fseek(f, 0, SEEK_END) != 0) { + return -1; + } + + n = ftell(f); + fseek(f, p, SEEK_SET); // file position restored + + return n; +} + + +// Memory handling ------------------------------------------------------------------ +// +// This is the interface to low-level memory management routines. By default a simple +// wrapping to malloc/free/realloc is provided, although there is a limit on the max +// amount of memoy that can be reclaimed. This is mostly as a safety feature to +// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms +// would never need. + +#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) + +// User may override this behaviour by using a memory plug-in, which basically replaces +// the default memory management functions. In this case, no check is performed and it +// is up to the plug-in writter to keep in the safe side. There are only three functions +// required to be implemented: malloc, realloc and free, although the user may want to +// replace the optional mallocZero, calloc and dup as well. + +cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); + +// ********************************************************************************* + +// This is the default memory allocation function. It does a very coarse +// check of amout of memory, just to prevent exploits +static +void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) +{ + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum + + return (void*) malloc(size); + + cmsUNUSED_PARAMETER(ContextID); +} + +// Generic allocate & zero +static +void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) +{ + void *pt = _cmsMalloc(ContextID, size); + if (pt == NULL) return NULL; + + memset(pt, 0, size); + return pt; +} + + +// The default free function. The only check proformed is against NULL pointers +static +void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) +{ + // free(NULL) is defined a no-op by C99, therefore it is safe to + // avoid the check, but it is here just in case... + + if (Ptr) free(Ptr); + + cmsUNUSED_PARAMETER(ContextID); +} + +// The default realloc function. Again it check for exploits. If Ptr is NULL, +// realloc behaves the same way as malloc and allocates a new block of size bytes. +static +void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) +{ + + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb + + return realloc(Ptr, size); + + cmsUNUSED_PARAMETER(ContextID); +} + + +// The default calloc function. Allocates an array of num elements, each one of size bytes +// all memory is initialized to zero. +static +void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) +{ + cmsUInt32Number Total = num * size; + + // Preserve calloc behaviour + if (Total == 0) return NULL; + + // Safe check for overflow. + if (num >= UINT_MAX / size) return NULL; + + // Check for overflow + if (Total < num || Total < size) { + return NULL; + } + + if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb + + return _cmsMallocZero(ContextID, Total); +} + +// Generic block duplication +static +void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) +{ + void* mem; + + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb + + mem = _cmsMalloc(ContextID, size); + + if (mem != NULL && Org != NULL) + memmove(mem, Org, size); + + return mem; +} + +// Pointers to malloc and _cmsFree functions in current environment +static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn; +static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn; +static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn; +static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn; +static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn; +static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn; + +// Plug-in replacement entry +cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) +{ + cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + + // NULL forces to reset to defaults + if (Data == NULL) { + + MallocPtr = _cmsMallocDefaultFn; + MallocZeroPtr= _cmsMallocZeroDefaultFn; + FreePtr = _cmsFreeDefaultFn; + ReallocPtr = _cmsReallocDefaultFn; + CallocPtr = _cmsCallocDefaultFn; + DupPtr = _cmsDupDefaultFn; + return TRUE; + } + + // Check for required callbacks + if (Plugin -> MallocPtr == NULL || + Plugin -> FreePtr == NULL || + Plugin -> ReallocPtr == NULL) return FALSE; + + // Set replacement functions + MallocPtr = Plugin -> MallocPtr; + FreePtr = Plugin -> FreePtr; + ReallocPtr = Plugin -> ReallocPtr; + + if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr; + if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr; + if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr; + + return TRUE; +} + +// Generic allocate +void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) +{ + return MallocPtr(ContextID, size); +} + +// Generic allocate & zero +void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) +{ + return MallocZeroPtr(ContextID, size); +} + +// Generic calloc +void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) +{ + return CallocPtr(ContextID, num, size); +} + +// Generic reallocate +void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) +{ + return ReallocPtr(ContextID, Ptr, size); +} + +// Generic free memory +void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) +{ + if (Ptr != NULL) FreePtr(ContextID, Ptr); +} + +// Generic block duplication +void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) +{ + return DupPtr(ContextID, Org, size); +} + +// ******************************************************************************************** + +// Sub allocation takes care of many pointers of small size. The memory allocated in +// this way have be freed at once. Next function allocates a single chunk for linked list +// I prefer this method over realloc due to the big inpact on xput realloc may have if +// memory is being swapped to disk. This approach is safer (although thats not true on any platform) +static +_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) +{ + _cmsSubAllocator_chunk* chunk; + + // Create the container + chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk)); + if (chunk == NULL) return NULL; + + // Initialize values + chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial); + if (chunk ->Block == NULL) { + + // Something went wrong + _cmsFree(ContextID, chunk); + return NULL; + } + + // 20K by default + if (Initial == 0) + Initial = 20*1024; + + chunk ->BlockSize = Initial; + chunk ->Used = 0; + chunk ->next = NULL; + + return chunk; +} + +// The suballocated is nothing but a pointer to the first element in the list. We also keep +// the thread ID in this structure. +_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial) +{ + _cmsSubAllocator* sub; + + // Create the container + sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator)); + if (sub == NULL) return NULL; + + sub ->ContextID = ContextID; + + sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial); + if (sub ->h == NULL) { + _cmsFree(ContextID, sub); + return NULL; + } + + return sub; +} + + +// Get rid of whole linked list +void _cmsSubAllocDestroy(_cmsSubAllocator* sub) +{ + _cmsSubAllocator_chunk *chunk, *n; + + for (chunk = sub ->h; chunk != NULL; chunk = n) { + + n = chunk->next; + if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block); + _cmsFree(sub ->ContextID, chunk); + } + + // Free the header + _cmsFree(sub ->ContextID, sub); +} + + +// Get a pointer to small memory block. +void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) +{ + cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; + cmsUInt8Number* ptr; + + size = _cmsALIGNLONG(size); + + // Check for memory. If there is no room, allocate a new chunk of double memory size. + if (size > Free) { + + _cmsSubAllocator_chunk* chunk; + cmsUInt32Number newSize; + + newSize = sub -> h ->BlockSize * 2; + if (newSize < size) newSize = size; + + chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize); + if (chunk == NULL) return NULL; + + // Link list + chunk ->next = sub ->h; + sub ->h = chunk; + + } + + ptr = sub -> h ->Block + sub -> h ->Used; + sub -> h -> Used += size; + + return (void*) ptr; +} + +// Error logging ****************************************************************** + +// There is no error handling at all. When a funtion fails, it returns proper value. +// For example, all create functions does return NULL on failure. Other return FALSE +// It may be interesting, for the developer, to know why the function is failing. +// for that reason, lcms2 does offer a logging function. This function does recive +// a ENGLISH string with some clues on what is going wrong. You can show this +// info to the end user, or just create some sort of log. +// The logging function should NOT terminate the program, as this obviously can leave +// resources. It is the programmer's responsability to check each function return code +// to make sure it didn't fail. + +// Error messages are limited to MAX_ERROR_MESSAGE_LEN + +#define MAX_ERROR_MESSAGE_LEN 1024 + +// --------------------------------------------------------------------------------------------------------- + +// This is our default log error +static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); + +// The current handler in actual environment +static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction; + +// The default error logger does nothing. +static +void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) +{ + // fprintf(stderr, "[lcms]: %s\n", Text); + // fflush(stderr); + + cmsUNUSED_PARAMETER(ContextID); + cmsUNUSED_PARAMETER(ErrorCode); + cmsUNUSED_PARAMETER(Text); +} + +// Change log error +void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) +{ + if (Fn == NULL) + LogErrorHandler = DefaultLogErrorHandlerFunction; + else + LogErrorHandler = Fn; +} + +// Log an error +// ErrorText is a text holding an english description of error. +void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) +{ + va_list args; + char Buffer[MAX_ERROR_MESSAGE_LEN]; + + va_start(args, ErrorText); + vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); + va_end(args); + + // Call handler + LogErrorHandler(ContextID, ErrorCode, Buffer); +} + +// Utility function to print signatures +void _cmsTagSignature2String(char String[5], cmsTagSignature sig) +{ + cmsUInt32Number be; + + // Convert to big endian + be = _cmsAdjustEndianess32((cmsUInt32Number) sig); + + // Move chars + memmove(String, &be, 4); + + // Make sure of terminator + String[4] = 0; +} + diff --git a/thirdparty/liblcms2/src/cmsgamma.c b/thirdparty/liblcms2/src/cmsgamma.c new file mode 100644 index 00000000..db156c75 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsgamma.c @@ -0,0 +1,1138 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +#include "lcms2_internal.h" + +// Tone curves are powerful constructs that can contain curves specified in diverse ways. +// The curve is stored in segments, where each segment can be sampled or specified by parameters. +// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation, +// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes, +// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function, +// the plug-in should provide the type id, how many parameters each type has, and a pointer to +// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will +// be called with the type id as a negative value, and a sampled version of the reversed curve +// will be built. + +// ----------------------------------------------------------------- Implementation +// Maxim number of nodes +#define MAX_NODES_IN_CURVE 4097 +#define MINUS_INF (-1E22F) +#define PLUS_INF (+1E22F) + +// The list of supported parametric curves +typedef struct _cmsParametricCurvesCollection_st { + + int nFunctions; // Number of supported functions in this chunk + int FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types + int ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function + cmsParametricCurveEvaluator Evaluator; // The evaluator + + struct _cmsParametricCurvesCollection_st* Next; // Next in list + +} _cmsParametricCurvesCollection; + + +// This is the default (built-in) evaluator +static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); + +// The built-in list +static _cmsParametricCurvesCollection DefaultCurves = { + 9, // # of curve types + { 1, 2, 3, 4, 5, 6, 7, 8, 108 }, // Parametric curve ID + { 1, 3, 4, 5, 7, 4, 5, 5, 1 }, // Parameters by type + DefaultEvalParametricFn, // Evaluator + NULL // Next in chain +}; + +// The linked list head +static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; + +// As a way to install new parametric curves +cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data) +{ + cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; + _cmsParametricCurvesCollection* fl; + + if (Data == NULL) { + + ParametricCurves = &DefaultCurves; + return TRUE; + } + + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(sizeof(_cmsParametricCurvesCollection)); + if (fl == NULL) return FALSE; + + // Copy the parameters + fl ->Evaluator = Plugin ->Evaluator; + fl ->nFunctions = Plugin ->nFunctions; + + // Make sure no mem overwrites + if (fl ->nFunctions > MAX_TYPES_IN_LCMS_PLUGIN) + fl ->nFunctions = MAX_TYPES_IN_LCMS_PLUGIN; + + // Copy the data + memmove(fl->FunctionTypes, Plugin ->FunctionTypes, fl->nFunctions * sizeof(cmsUInt32Number)); + memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); + + // Keep linked list + fl ->Next = ParametricCurves; + ParametricCurves = fl; + + // All is ok + return TRUE; +} + + +// Search in type list, return position or -1 if not found +static +int IsInSet(int Type, _cmsParametricCurvesCollection* c) +{ + int i; + + for (i=0; i < c ->nFunctions; i++) + if (abs(Type) == c ->FunctionTypes[i]) return i; + + return -1; +} + + +// Search for the collection which contains a specific type +static +_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index) +{ + _cmsParametricCurvesCollection* c; + int Position; + + for (c = ParametricCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); + + if (Position != -1) { + if (index != NULL) + *index = Position; + return c; + } + } + + return NULL; +} + +// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case +// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the +// optimization curve is given. Both features simultaneously is an error +static +cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries, + cmsInt32Number nSegments, const cmsCurveSegment* Segments, + const cmsUInt16Number* Values) +{ + cmsToneCurve* p; + int i; + + // We allow huge tables, which are then restricted for smoothing operations + if (nEntries > 65530 || nEntries < 0) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries"); + return NULL; + } + + if (nEntries <= 0 && nSegments <= 0) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table"); + return NULL; + } + + // Allocate all required pointers, etc. + p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve)); + if (!p) return NULL; + + // In this case, there are no segments + if (nSegments <= 0) { + p ->Segments = NULL; + p ->Evals = NULL; + } + else { + p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment)); + if (p ->Segments == NULL) goto Error; + + p ->Evals = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator)); + if (p ->Evals == NULL) goto Error; + } + + p -> nSegments = nSegments; + + // This 16-bit table contains a limited precision representation of the whole curve and is kept for + // increasing xput on certain operations. + if (nEntries <= 0) { + p ->Table16 = NULL; + } + else { + p ->Table16 = (cmsUInt16Number*) _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number)); + if (p ->Table16 == NULL) goto Error; + } + + p -> nEntries = nEntries; + + // Initialize members if requested + if (Values != NULL && (nEntries > 0)) { + + for (i=0; i < nEntries; i++) + p ->Table16[i] = Values[i]; + } + + // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it + // is placed in advance to maximize performance. + if (Segments != NULL && (nSegments > 0)) { + + _cmsParametricCurvesCollection *c; + + p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*)); + if (p ->SegInterp == NULL) goto Error; + + for (i=0; i< nSegments; i++) { + + // Type 0 is a special marker for table-based curves + if (Segments[i].Type == 0) + p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT); + + memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment)); + + if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL) + p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints); + else + p ->Segments[i].SampledPoints = NULL; + + + c = GetParametricCurveByType(Segments[i].Type, NULL); + if (c != NULL) + p ->Evals[i] = c ->Evaluator; + } + } + + p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); + return p; + +Error: + if (p -> Segments) _cmsFree(ContextID, p ->Segments); + if (p -> Evals) _cmsFree(ContextID, p -> Evals); + if (p ->Table16) _cmsFree(ContextID, p ->Table16); + _cmsFree(ContextID, p); + return NULL; +} + + +// Parametric Fn using floating point +static +cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R) +{ + cmsFloat64Number e, Val, disc; + + switch (Type) { + + // X = Y ^ Gamma + case 1: + if (R < 0) + Val = 0; + else + Val = pow(R, Params[0]); + break; + + // Type 1 Reversed: X = Y ^1/gamma + case -1: + if (R < 0) + Val = 0; + else + Val = pow(R, 1/Params[0]); + break; + + // CIE 122-1966 + // Y = (aX + b)^Gamma | X >= -b/a + // Y = 0 | else + case 2: + disc = -Params[2] / Params[1]; + + if (R >= disc ) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]); + else + Val = 0; + } + else + Val = 0; + break; + + // Type 2 Reversed + // X = (Y ^1/g - b) / a + case -2: + if (R < 0) + Val = 0; + else + Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; + + if (Val < 0) + Val = 0; + break; + + + // IEC 61966-3 + // Y = (aX + b)^Gamma | X <= -b/a + // Y = c | else + case 3: + disc = -Params[2] / Params[1]; + if (disc < 0) + disc = 0; + + if (R >= disc) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]) + Params[3]; + else + Val = 0; + } + else + Val = Params[3]; + break; + + + // Type 3 reversed + // X=((Y-c)^1/g - b)/a | (Y>=c) + // X=-b/a | (Y= Params[3]) { + + e = R - Params[3]; + + if (e > 0) + Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1]; + else + Val = 0; + } + else { + Val = -Params[2] / Params[1]; + } + break; + + + // IEC 61966-2.1 (sRGB) + // Y = (aX + b)^Gamma | X >= d + // Y = cX | X < d + case 4: + if (R >= Params[4]) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]); + else + Val = 0; + } + else + Val = R * Params[3]; + break; + + // Type 4 reversed + // X=((Y^1/g-b)/a) | Y >= (ad+b)^g + // X=Y/c | Y< (ad+b)^g + case -4: + e = Params[1] * Params[4] + Params[2]; + if (e < 0) + disc = 0; + else + disc = pow(e, Params[0]); + + if (R >= disc) { + + Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; + } + else { + Val = R / Params[3]; + } + break; + + + // Y = (aX + b)^Gamma + e | X >= d + // Y = cX + f | X < d + case 5: + if (R >= Params[4]) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]) + Params[5]; + else + Val = 0; + } + else + Val = R*Params[3] + Params[6]; + break; + + + // Reversed type 5 + // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f + // X=(Y-f)/c | else + case -5: + + disc = Params[3] * Params[4] + Params[6]; + if (R >= disc) { + + e = R - Params[5]; + if (e < 0) + Val = 0; + else + Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1]; + } + else { + Val = (R - Params[6]) / Params[3]; + } + break; + + + // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf + // Type 6 is basically identical to type 5 without d + + // Y = (a * X + b) ^ Gamma + c + case 6: + e = Params[1]*R + Params[2]; + + if (e < 0) + Val = 0; + else + Val = pow(e, Params[0]) + Params[3]; + break; + + // ((Y - c) ^1/Gamma - b) / a + case -6: + e = R - Params[3]; + if (e < 0) + Val = 0; + else + Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1]; + break; + + + // Y = a * log (b * X^Gamma + c) + d + case 7: + + e = Params[2] * pow(R, Params[0]) + Params[3]; + if (e <= 0) + Val = 0; + else + Val = Params[1]*log10(e) + Params[4]; + break; + + // (Y - d) / a = log(b * X ^Gamma + c) + // pow(10, (Y-d) / a) = b * X ^Gamma + c + // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X + case -7: + Val = pow((pow(10.0, (R-Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]); + break; + + + //Y = a * b^(c*X+d) + e + case 8: + Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]); + break; + + + // Y = (log((y-e) / a) / log(b) - d ) / c + // a=0, b=1, c=2, d=3, e=4, + case -8: + + disc = R - Params[4]; + if (disc < 0) Val = 0; + else + Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2]; + break; + + // S-Shaped: (1 - (1-x)^1/g)^1/g + case 108: + Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]); + break; + + // y = (1 - (1-x)^1/g)^1/g + // y^g = (1 - (1-x)^1/g) + // 1 - y^g = (1-x)^1/g + // (1 - y^g)^g = 1 - x + // 1 - (1 - y^g)^g + case -108: + Val = 1 - pow(1 - pow(R, Params[0]), Params[0]); + break; + + default: + // Unsupported parametric curve. Should never reach here + return 0; + } + + return Val; +} + +// Evaluate a segmented funtion for a single value. Return -1 if no valid segment found . +// If fn type is 0, perform an interpolation on the table +static +cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) +{ + int i; + + for (i = g ->nSegments-1; i >= 0 ; --i) { + + // Check for domain + if ((R > g ->Segments[i].x0) && (R <= g ->Segments[i].x1)) { + + // Type == 0 means segment is sampled + if (g ->Segments[i].Type == 0) { + + cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0); + cmsFloat32Number Out; + + // Setup the table (TODO: clean that) + g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints; + + g ->SegInterp[i] -> Interpolation.LerpFloat(&R1, &Out, g ->SegInterp[i]); + + return Out; + } + else + return g ->Evals[i](g->Segments[i].Type, g ->Segments[i].Params, R); + } + } + + return MINUS_INF; +} + + +// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the +// floating point description empty. +cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number Values[]) +{ + return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values); +} + +static +int EntriesByGamma(cmsFloat64Number Gamma) +{ + if (fabs(Gamma - 1.0) < 0.001) return 2; + return 4096; +} + + +// Create a segmented gamma, fill the table +cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, + cmsInt32Number nSegments, const cmsCurveSegment Segments[]) +{ + int i; + cmsFloat64Number R, Val; + cmsToneCurve* g; + int nGridPoints = 4096; + + _cmsAssert(Segments != NULL); + + // Optimizatin for identity curves. + if (nSegments == 1 && Segments[0].Type == 1) { + + nGridPoints = EntriesByGamma(Segments[0].Params[0]); + } + + g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL); + if (g == NULL) return NULL; + + // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries + // for performance reasons. This table would normally not be used except on 8/16 bits transforms. + for (i=0; i < nGridPoints; i++) { + + R = (cmsFloat64Number) i / (nGridPoints-1); + + Val = EvalSegmentedFn(g, R); + + // Round and saturate + g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0); + } + + return g; +} + +// Use a segmented curve to store the floating point table +cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]) +{ + cmsCurveSegment Seg[2]; + + // Initialize segmented curve part up to 0 + Seg[0].x0 = -1; + Seg[0].x1 = 0; + Seg[0].Type = 6; + + Seg[0].Params[0] = 1; + Seg[0].Params[1] = 0; + Seg[0].Params[2] = 0; + Seg[0].Params[3] = 0; + Seg[0].Params[4] = 0; + + // From zero to any + Seg[1].x0 = 0; + Seg[1].x1 = 1.0; + Seg[1].Type = 0; + + Seg[1].nGridPoints = nEntries; + Seg[1].SampledPoints = (cmsFloat32Number*) values; + + return cmsBuildSegmentedToneCurve(ContextID, 2, Seg); +} + +// Parametric curves +// +// Parameters goes as: Curve, a, b, c, d, e, f +// Type is the ICC type +1 +// if type is negative, then the curve is analyticaly inverted +cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]) +{ + cmsCurveSegment Seg0; + int Pos = 0; + cmsUInt32Number size; + _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos); + + _cmsAssert(Params != NULL); + + if (c == NULL) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); + return NULL; + } + + memset(&Seg0, 0, sizeof(Seg0)); + + Seg0.x0 = MINUS_INF; + Seg0.x1 = PLUS_INF; + Seg0.Type = Type; + + size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number); + memmove(Seg0.Params, Params, size); + + return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0); +} + + + +// Build a gamma table based on gamma constant +cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma) +{ + return cmsBuildParametricToneCurve(ContextID, 1, &Gamma); +} + + +// Free all memory taken by the gamma curve +void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) +{ + cmsContext ContextID; + + if (Curve == NULL) return; + + ContextID = Curve ->InterpParams->ContextID; + + _cmsFreeInterpParams(Curve ->InterpParams); + + if (Curve -> Table16) + _cmsFree(ContextID, Curve ->Table16); + + if (Curve ->Segments) { + + cmsUInt32Number i; + + for (i=0; i < Curve ->nSegments; i++) { + + if (Curve ->Segments[i].SampledPoints) { + _cmsFree(ContextID, Curve ->Segments[i].SampledPoints); + } + + if (Curve ->SegInterp[i] != 0) + _cmsFreeInterpParams(Curve->SegInterp[i]); + } + + _cmsFree(ContextID, Curve ->Segments); + _cmsFree(ContextID, Curve ->SegInterp); + } + + if (Curve -> Evals) + _cmsFree(ContextID, Curve -> Evals); + + if (Curve) _cmsFree(ContextID, Curve); +} + +// Utility function, free 3 gamma tables +void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) +{ + + _cmsAssert(Curve != NULL); + + if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]); + if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]); + if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]); + + Curve[0] = Curve[1] = Curve[2] = NULL; +} + + +// Duplicate a gamma table +cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) +{ + if (In == NULL) return NULL; + + return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); +} + +// Joins two curves for X and Y. Curves should be monotonic. +// We want to get +// +// y = Y^-1(X(t)) +// +cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, + const cmsToneCurve* X, + const cmsToneCurve* Y, cmsUInt32Number nResultingPoints) +{ + cmsToneCurve* out = NULL; + cmsToneCurve* Yreversed = NULL; + cmsFloat32Number t, x; + cmsFloat32Number* Res = NULL; + cmsUInt32Number i; + + + _cmsAssert(X != NULL); + _cmsAssert(Y != NULL); + + Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y); + if (Yreversed == NULL) goto Error; + + Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number)); + if (Res == NULL) goto Error; + + //Iterate + for (i=0; i < nResultingPoints; i++) { + + t = (cmsFloat32Number) i / (nResultingPoints-1); + x = cmsEvalToneCurveFloat(X, t); + Res[i] = cmsEvalToneCurveFloat(Yreversed, x); + } + + // Allocate space for output + out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res); + +Error: + + if (Res != NULL) _cmsFree(ContextID, Res); + if (Yreversed != NULL) cmsFreeToneCurve(Yreversed); + + return out; +} + + + +// Get the surrounding nodes. This is tricky on non-monotonic tables +static +int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p) +{ + int i; + int y0, y1; + + // A 1 point table is not allowed + if (p -> Domain[0] < 1) return -1; + + // Let's see if ascending or descending. + if (LutTable[0] < LutTable[p ->Domain[0]]) { + + // Table is overall ascending + for (i=p->Domain[0]-1; i >=0; --i) { + + y0 = LutTable[i]; + y1 = LutTable[i+1]; + + if (y0 <= y1) { // Increasing + if (In >= y0 && In <= y1) return i; + } + else + if (y1 < y0) { // Decreasing + if (In >= y1 && In <= y0) return i; + } + } + } + else { + // Table is overall descending + for (i=0; i < (int) p -> Domain[0]; i++) { + + y0 = LutTable[i]; + y1 = LutTable[i+1]; + + if (y0 <= y1) { // Increasing + if (In >= y0 && In <= y1) return i; + } + else + if (y1 < y0) { // Decreasing + if (In >= y1 && In <= y0) return i; + } + } + } + + return -1; +} + +// Reverse a gamma table +cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve) +{ + cmsToneCurve *out; + cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2; + int i, j; + int Ascending; + + _cmsAssert(InCurve != NULL); + + // Try to reverse it analytically whatever possible + if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) { + + return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, + -(InCurve -> Segments[0].Type), + InCurve -> Segments[0].Params); + } + + // Nope, reverse the table. + out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL); + if (out == NULL) + return NULL; + + // We want to know if this is an ascending or descending table + Ascending = !cmsIsToneCurveDescending(InCurve); + + // Iterate across Y axis + for (i=0; i < nResultSamples; i++) { + + y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1); + + // Find interval in which y is within. + j = GetInterval(y, InCurve->Table16, InCurve->InterpParams); + if (j >= 0) { + + + // Get limits of interval + x1 = InCurve ->Table16[j]; + x2 = InCurve ->Table16[j+1]; + + y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1); + y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1); + + // If collapsed, then use any + if (x1 == x2) { + + out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1); + continue; + + } else { + + // Interpolate + a = (y2 - y1) / (x2 - x1); + b = y2 - a * x2; + } + } + + out ->Table16[i] = _cmsQuickSaturateWord(a* y + b); + } + + + return out; +} + +// Reverse a gamma table +cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma) +{ + _cmsAssert(InGamma != NULL); + + return cmsReverseToneCurveEx(4096, InGamma); +} + +// From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite +// differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press. +// +// Smoothing and interpolation with second differences. +// +// Input: weights (w), data (y): vector from 1 to m. +// Input: smoothing parameter (lambda), length (m). +// Output: smoothed vector (z): vector from 1 to m. + +static +cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[], cmsFloat32Number z[], cmsFloat32Number lambda, int m) +{ + int i, i1, i2; + cmsFloat32Number *c, *d, *e; + cmsBool st; + + + c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); + d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); + e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); + + if (c != NULL && d != NULL && e != NULL) { + + + d[1] = w[1] + lambda; + c[1] = -2 * lambda / d[1]; + e[1] = lambda /d[1]; + z[1] = w[1] * y[1]; + d[2] = w[2] + 5 * lambda - d[1] * c[1] * c[1]; + c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2]; + e[2] = lambda / d[2]; + z[2] = w[2] * y[2] - c[1] * z[1]; + + for (i = 3; i < m - 1; i++) { + i1 = i - 1; i2 = i - 2; + d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i]; + e[i] = lambda / d[i]; + z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2]; + } + + i1 = m - 2; i2 = m - 3; + + d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1]; + z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2]; + i1 = m - 1; i2 = m - 2; + + d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m]; + z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m]; + + for (i = m - 2; 1<= i; i--) + z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2]; + + st = TRUE; + } + else st = FALSE; + + if (c != NULL) _cmsFree(ContextID, c); + if (d != NULL) _cmsFree(ContextID, d); + if (e != NULL) _cmsFree(ContextID, e); + + return st; +} + +// Smooths a curve sampled at regular intervals. +cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda) +{ + cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE]; + int i, nItems, Zeros, Poles; + + if (Tab == NULL) return FALSE; + + if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do + + nItems = Tab -> nEntries; + + if (nItems >= MAX_NODES_IN_CURVE) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: too many points."); + return FALSE; + } + + memset(w, 0, nItems * sizeof(cmsFloat32Number)); + memset(y, 0, nItems * sizeof(cmsFloat32Number)); + memset(z, 0, nItems * sizeof(cmsFloat32Number)); + + for (i=0; i < nItems; i++) + { + y[i+1] = (cmsFloat32Number) Tab -> Table16[i]; + w[i+1] = 1.0; + } + + if (!smooth2(Tab ->InterpParams->ContextID, w, y, z, (cmsFloat32Number) lambda, nItems)) return FALSE; + + // Do some reality - checking... + Zeros = Poles = 0; + for (i=nItems; i > 1; --i) { + + if (z[i] == 0.) Zeros++; + if (z[i] >= 65535.) Poles++; + if (z[i] < z[i-1]) return FALSE; // Non-Monotonic + } + + if (Zeros > (nItems / 3)) return FALSE; // Degenerated, mostly zeros + if (Poles > (nItems / 3)) return FALSE; // Degenerated, mostly poles + + // Seems ok + for (i=0; i < nItems; i++) { + + // Clamp to cmsUInt16Number + Tab -> Table16[i] = _cmsQuickSaturateWord(z[i+1]); + } + + return TRUE; +} + +// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting +// in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases. +cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve) +{ + cmsUInt32Number i; + int diff; + + _cmsAssert(Curve != NULL); + + for (i=0; i < Curve ->nEntries; i++) { + + diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries)); + if (diff > 0x0f) + return FALSE; + } + + return TRUE; +} + +// Same, but for monotonicity +cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t) +{ + int n; + int i, last; + + _cmsAssert(t != NULL); + + n = t ->nEntries; + last = t ->Table16[n-1]; + + for (i = n-2; i >= 0; --i) { + + if (t ->Table16[i] > last) + + return FALSE; + else + last = t ->Table16[i]; + + } + + return TRUE; +} + +// Same, but for descending tables +cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + return t ->Table16[0] > t ->Table16[t ->nEntries-1]; +} + + +// Another info fn: is out gamma table multisegment? +cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + return t -> nSegments > 1; +} + +cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + if (t -> nSegments != 1) return 0; + return t ->Segments[0].Type; +} + +// We need accuracy this time +cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v) +{ + _cmsAssert(Curve != NULL); + + // Check for 16 bits table. If so, this is a limited-precision tone curve + if (Curve ->nSegments == 0) { + + cmsUInt16Number In, Out; + + In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0); + Out = cmsEvalToneCurve16(Curve, In); + + return (cmsFloat32Number) (Out / 65535.0); + } + + return (cmsFloat32Number) EvalSegmentedFn(Curve, v); +} + +// We need xput over here +cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v) +{ + cmsUInt16Number out; + + _cmsAssert(Curve != NULL); + + Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams); + return out; +} + + +// Least squares fitting. +// A mathematical procedure for finding the best-fitting curve to a given set of points by +// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve. +// The sum of the squares of the offsets is used instead of the offset absolute values because +// this allows the residuals to be treated as a continuous differentiable quantity. +// +// y = f(x) = x ^ g +// +// R = (yi - (xi^g)) +// R2 = (yi - (xi^g))2 +// SUM R2 = SUM (yi - (xi^g))2 +// +// dR2/dg = -2 SUM x^g log(x)(y - x^g) +// solving for dR2/dg = 0 +// +// g = 1/n * SUM(log(y) / log(x)) + +cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision) +{ + cmsFloat64Number gamma, sum, sum2; + cmsFloat64Number n, x, y, Std; + cmsUInt32Number i; + + _cmsAssert(t != NULL); + + sum = sum2 = n = 0; + + // Excluding endpoints + for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) { + + x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1); + y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x); + + // Avoid 7% on lower part to prevent + // artifacts due to linear ramps + + if (y > 0. && y < 1. && x > 0.07) { + + gamma = log(y) / log(x); + sum += gamma; + sum2 += gamma * gamma; + n++; + } + } + + // Take a look on SD to see if gamma isn't exponential at all + Std = sqrt((n * sum2 - sum * sum) / (n*(n-1))); + + if (Std > Precision) + return -1.0; + + return (sum / n); // The mean +} diff --git a/thirdparty/liblcms2/src/cmsgmt.c b/thirdparty/liblcms2/src/cmsgmt.c new file mode 100644 index 00000000..c2f3a9a5 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsgmt.c @@ -0,0 +1,591 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// Auxiliar: append a Lab identity after the given sequence of profiles +// and return the transform. Lab profile is closed, rest of profiles are kept open. +cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsHTRANSFORM xform; + cmsHPROFILE hLab; + cmsHPROFILE ProfileList[256]; + cmsBool BPCList[256]; + cmsFloat64Number AdaptationList[256]; + cmsUInt32Number IntentList[256]; + cmsUInt32Number i; + + // This is a rather big number and there is no need of dynamic memory + // since we are adding a profile, 254 + 1 = 255 and this is the limit + if (nProfiles > 254) return NULL; + + // The output space + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return NULL; + + // Create a copy of parameters + for (i=0; i < nProfiles; i++) { + + ProfileList[i] = hProfiles[i]; + BPCList[i] = BPC[i]; + AdaptationList[i] = AdaptationStates[i]; + IntentList[i] = Intents[i]; + } + + // Place Lab identity at chain's end. + ProfileList[nProfiles] = hLab; + BPCList[nProfiles] = 0; + AdaptationList[nProfiles] = 1.0; + IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC; + + // Create the transform + xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList, + BPCList, + IntentList, + AdaptationList, + NULL, 0, + InputFormat, + OutputFormat, + dwFlags); + + cmsCloseProfile(hLab); + + return xform; +} + + +// Compute K -> L* relationship. Flags may include black point compensation. In this case, +// the relationship is assumed from the profile with BPC to a black point zero. +static +cmsToneCurve* ComputeKToLstar(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsToneCurve* out = NULL; + cmsUInt32Number i; + cmsHTRANSFORM xform; + cmsCIELab Lab; + cmsFloat32Number cmyk[4]; + cmsFloat32Number* SampledPoints; + + xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (xform == NULL) return NULL; + + SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); + if (SampledPoints == NULL) goto Error; + + for (i=0; i < nPoints; i++) { + + cmyk[0] = 0; + cmyk[1] = 0; + cmyk[2] = 0; + cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); + + cmsDoTransform(xform, cmyk, &Lab, 1); + SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation + } + + out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); + +Error: + + cmsDeleteTransform(xform); + if (SampledPoints) _cmsFree(ContextID, SampledPoints); + + return out; +} + + +// Compute Black tone curve on a CMYK -> CMYK transform. This is done by +// using the proof direction on both profiles to find K->L* relationship +// then joining both curves. dwFlags may include black point compensation. +cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsToneCurve *in, *out, *KTone; + + // Make sure CMYK -> CMYK + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL; + + + // Make sure last is an output profile + if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL; + + // Create individual curves. BPC works also as each K to L* is + // computed as a BPC to zero black point in case of L* + in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (in == NULL) return NULL; + + out = ComputeKToLstar(ContextID, nPoints, 1, + Intents + (nProfiles - 1), + hProfiles + (nProfiles - 1), + BPC + (nProfiles - 1), + AdaptationStates + (nProfiles - 1), + dwFlags); + if (out == NULL) { + cmsFreeToneCurve(in); + return NULL; + } + + // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but + // since this is used on black-preserving LUTs, we are not loosing accuracy in any case + KTone = cmsJoinToneCurve(ContextID, in, out, nPoints); + + // Get rid of components + cmsFreeToneCurve(in); cmsFreeToneCurve(out); + + // Something went wrong... + if (KTone == NULL) return NULL; + + // Make sure it is monotonic + if (!cmsIsToneCurveMonotonic(KTone)) { + + cmsFreeToneCurve(KTone); + return NULL; + } + + return KTone; +} + + +// Gamut LUT Creation ----------------------------------------------------------------------------------------- + +// Used by gamut & softproofing + +typedef struct { + + cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL + cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back + cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut + + } GAMUTCHAIN; + +// This sampler does compute gamut boundaries by comparing original +// values with a transform going back and forth. Values above ERR_THERESHOLD +// of maximum are considered out of gamut. + +#define ERR_THERESHOLD 5 + + +static +int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; + cmsCIELab LabIn1, LabOut1; + cmsCIELab LabIn2, LabOut2; + cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; + cmsFloat64Number dE1, dE2, ErrorRatio; + + // Assume in-gamut by default. + dE1 = 0.; + dE2 = 0; + ErrorRatio = 1.0; + + // Convert input to Lab + if (t -> hInput != NULL) + cmsDoTransform(t -> hInput, In, &LabIn1, 1); + + // converts from PCS to colorant. This always + // does return in-gamut values, + cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); + + // Now, do the inverse, from colorant to PCS. + cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); + + memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); + + // Try again, but this time taking Check as input + cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); + cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); + + // Take difference of direct value + dE1 = cmsDeltaE(&LabIn1, &LabOut1); + + // Take difference of converted value + dE2 = cmsDeltaE(&LabIn2, &LabOut2); + + + // if dE1 is small and dE2 is small, value is likely to be in gamut + if (dE1 < t->Thereshold && dE2 < t->Thereshold) + Out[0] = 0; + else { + + // if dE1 is small and dE2 is big, undefined. Assume in gamut + if (dE1 < t->Thereshold && dE2 > t->Thereshold) + Out[0] = 0; + else + // dE1 is big and dE2 is small, clearly out of gamut + if (dE1 > t->Thereshold && dE2 < t->Thereshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); + else { + + // dE1 is big and dE2 is also big, could be due to perceptual mapping + // so take error ratio + if (dE2 == 0.0) + ErrorRatio = dE1; + else + ErrorRatio = dE1 / dE2; + + if (ErrorRatio > t->Thereshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); + else + Out[0] = 0; + } + } + + + return TRUE; +} + +// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs +// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE +// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well. +// +// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors, +// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should. + +cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number nGamutPCSposition, + cmsHPROFILE hGamut) +{ + cmsHPROFILE hLab; + cmsPipeline* Gamut; + cmsStage* CLUT; + cmsUInt32Number dwFormat; + GAMUTCHAIN Chain; + int nChannels, nGridpoints; + cmsColorSpaceSignature ColorSpace; + cmsUInt32Number i; + cmsHPROFILE ProfileList[256]; + cmsBool BPCList[256]; + cmsFloat64Number AdaptationList[256]; + cmsUInt32Number IntentList[256]; + + memset(&Chain, 0, sizeof(GAMUTCHAIN)); + + + if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition); + return NULL; + } + + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return NULL; + + + // The figure of merit. On matrix-shaper profiles, should be almost zero as + // the conversion is pretty exact. On LUT based profiles, different resolutions + // of input and output CLUT may result in differences. + + if (cmsIsMatrixShaper(hGamut)) { + + Chain.Thereshold = 1.0; + } + else { + Chain.Thereshold = ERR_THERESHOLD; + } + + + // Create a copy of parameters + for (i=0; i < nGamutPCSposition; i++) { + ProfileList[i] = hProfiles[i]; + BPCList[i] = BPC[i]; + AdaptationList[i] = AdaptationStates[i]; + IntentList[i] = Intents[i]; + } + + // Fill Lab identity + ProfileList[nGamutPCSposition] = hLab; + BPCList[nGamutPCSposition] = 0; + AdaptationList[nGamutPCSposition] = 1.0; + Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; + + + ColorSpace = cmsGetColorSpace(hGamut); + + nChannels = cmsChannelsOf(ColorSpace); + nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); + dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); + + // 16 bits to Lab double + Chain.hInput = cmsCreateExtendedTransform(ContextID, + nGamutPCSposition + 1, + ProfileList, + BPCList, + Intents, + AdaptationList, + NULL, 0, + dwFormat, TYPE_Lab_DBL, + cmsFLAGS_NOCACHE); + + + // Does create the forward step. Lab double to device + dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); + Chain.hForward = cmsCreateTransformTHR(ContextID, + hLab, TYPE_Lab_DBL, + hGamut, dwFormat, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); + + // Does create the backwards step + Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, + hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); + + + // All ok? + if (Chain.hForward && Chain.hReverse) { + + // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing + // dE when doing a transform back and forth on the colorimetric intent. + + Gamut = cmsPipelineAlloc(ContextID, 3, 1); + + if (Gamut != NULL) { + + CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); + cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT); + + cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); + } + } + else + Gamut = NULL; // Didn't work... + + // Free all needed stuff. + if (Chain.hInput) cmsDeleteTransform(Chain.hInput); + if (Chain.hForward) cmsDeleteTransform(Chain.hForward); + if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); + if (hLab) cmsCloseProfile(hLab); + + // And return computed hull + return Gamut; +} + +// Total Area Coverage estimation ---------------------------------------------------------------- + +typedef struct { + cmsUInt32Number nOutputChans; + cmsHTRANSFORM hRoundTrip; + cmsFloat32Number MaxTAC; + cmsFloat32Number MaxInput[cmsMAXCHANNELS]; + +} cmsTACestimator; + + +// This callback just accounts the maximum ink dropped in the given node. It does not populate any +// memory, as the destination table is NULL. Its only purpose it to know the global maximum. +static +int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) +{ + cmsTACestimator* bp = (cmsTACestimator*) Cargo; + cmsFloat32Number RoundTrip[cmsMAXCHANNELS]; + cmsUInt32Number i; + cmsFloat32Number Sum; + + + // Evaluate the xform + cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); + + // All all amounts of ink + for (Sum=0, i=0; i < bp ->nOutputChans; i++) + Sum += RoundTrip[i]; + + // If above maximum, keep track of input values + if (Sum > bp ->MaxTAC) { + + bp ->MaxTAC = Sum; + + for (i=0; i < bp ->nOutputChans; i++) { + bp ->MaxInput[i] = In[i]; + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(Out); +} + + +// Detect Total area coverage of the profile +cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) +{ + cmsTACestimator bp; + cmsUInt32Number dwFormatter; + cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; + cmsHPROFILE hLab; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // TAC only works on output profiles + if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { + return 0; + } + + // Create a fake formatter for result + dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); + + bp.nOutputChans = T_CHANNELS(dwFormatter); + bp.MaxTAC = 0; // Initial TAC is 0 + + // for safety + if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; + + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return 0; + // Setup a roundtrip on perceptual intent in output profile for TAC estimation + bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, + hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); + + cmsCloseProfile(hLab); + if (bp.hRoundTrip == NULL) return 0; + + // For L* we only need black and white. For C* we need many points + GridPoints[0] = 6; + GridPoints[1] = 74; + GridPoints[2] = 74; + + + if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { + bp.MaxTAC = 0; + } + + cmsDeleteTransform(bp.hRoundTrip); + + // Results in % + return bp.MaxTAC; +} + + +// Carefully, clamp on CIELab space. + +cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, + double amax, double amin, + double bmax, double bmin) +{ + + // Whole Luma surface to zero + + if (Lab -> L < 0) { + + Lab-> L = Lab->a = Lab-> b = 0.0; + return FALSE; + } + + // Clamp white, DISCARD HIGHLIGHTS. This is done + // in such way because icc spec doesn't allow the + // use of L>100 as a highlight means. + + if (Lab->L > 100) + Lab -> L = 100; + + // Check out gamut prism, on a, b faces + + if (Lab -> a < amin || Lab->a > amax|| + Lab -> b < bmin || Lab->b > bmax) { + + cmsCIELCh LCh; + double h, slope; + + // Falls outside a, b limits. Transports to LCh space, + // and then do the clipping + + + if (Lab -> a == 0.0) { // Is hue exactly 90? + + // atan will not work, so clamp here + Lab -> b = Lab->b < 0 ? bmin : bmax; + return TRUE; + } + + cmsLab2LCh(&LCh, Lab); + + slope = Lab -> b / Lab -> a; + h = LCh.h; + + // There are 4 zones + + if ((h >= 0. && h < 45.) || + (h >= 315 && h <= 360.)) { + + // clip by amax + Lab -> a = amax; + Lab -> b = amax * slope; + } + else + if (h >= 45. && h < 135.) + { + // clip by bmax + Lab -> b = bmax; + Lab -> a = bmax / slope; + } + else + if (h >= 135. && h < 225.) { + // clip by amin + Lab -> a = amin; + Lab -> b = amin * slope; + + } + else + if (h >= 225. && h < 315.) { + // clip by bmin + Lab -> b = bmin; + Lab -> a = bmin / slope; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "Invalid angle"); + return FALSE; + } + + } + + return TRUE; +} diff --git a/thirdparty/liblcms2/src/cmsintrp.c b/thirdparty/liblcms2/src/cmsintrp.c new file mode 100644 index 00000000..9aced860 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsintrp.c @@ -0,0 +1,1463 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// This module incorporates several interpolation routines, for 1 to 8 channels on input and +// up to 65535 channels on output. The user may change those by using the interpolation plug-in + +// Interpolation routines by default +static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); + +// This is the default factory +static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory; + + +// Main plug-in entry +cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) +{ + cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; + + if (Data == NULL) { + + Interpolators = DefaultInterpolatorsFactory; + return TRUE; + } + + // Set replacement functions + Interpolators = Plugin ->InterpolatorsFactory; + return TRUE; +} + + +// Set the interpolation method + +cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) +{ + // Invoke factory, possibly in the Plug-in + p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + + // If unsupported by the plug-in, go for the LittleCMS default. + // If happens only if an extern plug-in is being used + if (p ->Interpolation.Lerp16 == NULL) + p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags); + + // Check for valid interpolator (we just check one member of the union) + if (p ->Interpolation.Lerp16 == NULL) { + return FALSE; + } + return TRUE; +} + + +// This function precalculates as many parameters as possible to speed up the interpolation. +cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, + const cmsUInt32Number nSamples[], + int InputChan, int OutputChan, + const void *Table, + cmsUInt32Number dwFlags) +{ + cmsInterpParams* p; + int i; + + // Check for maximum inputs + if (InputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + + // Creates an empty object + p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams)); + if (p == NULL) return NULL; + + // Keep original parameters + p -> dwFlags = dwFlags; + p -> nInputs = InputChan; + p -> nOutputs = OutputChan; + p ->Table = Table; + p ->ContextID = ContextID; + + // Fill samples per input direction and domain (which is number of nodes minus one) + for (i=0; i < InputChan; i++) { + + p -> nSamples[i] = nSamples[i]; + p -> Domain[i] = nSamples[i] - 1; + } + + // Compute factors to apply to each component to index the grid array + p -> opta[0] = p -> nOutputs; + for (i=1; i < InputChan; i++) + p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; + + + if (!_cmsSetInterpolationRoutine(p)) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); + _cmsFree(ContextID, p); + return NULL; + } + + // All seems ok + return p; +} + + +// This one is a wrapper on the anterior, but assuming all directions have same number of nodes +cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags) +{ + int i; + cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS]; + + // Fill the auxiliar array + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Samples[i] = nSamples; + + // Call the extended function + return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags); +} + + +// Free all associated memory +void _cmsFreeInterpParams(cmsInterpParams* p) +{ + if (p != NULL) _cmsFree(p ->ContextID, p); +} + + +// Inline fixed point interpolation +cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h) +{ + cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000; + dif = (dif >> 16) + l; + return (cmsUInt16Number) (dif); +} + + +// Linear interpolation (Fixed-point optimized) +static +void LinLerp1D(register const cmsUInt16Number Value[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p) +{ + cmsUInt16Number y1, y0; + int cell0, rest; + int val3; + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + + // if last value... + if (Value[0] == 0xffff) { + + Output[0] = LutTable[p -> Domain[0]]; + return; + } + + val3 = p -> Domain[0] * Value[0]; + val3 = _cmsToFixedDomain(val3); // To fixed 15.16 + + cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits + rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits + + y0 = LutTable[cell0]; + y1 = LutTable[cell0+1]; + + + Output[0] = LinearInterp(rest, y0, y1); +} + + +// Floating-point version of 1D interpolation +static +void LinLerp1Dfloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + cmsFloat32Number y1, y0; + cmsFloat32Number val2, rest; + int cell0, cell1; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + + // if last value... + if (Value[0] == 1.0) { + Output[0] = LutTable[p -> Domain[0]]; + return; + } + + val2 = p -> Domain[0] * Value[0]; + + cell0 = (int) floor(val2); + cell1 = (int) ceil(val2); + + // Rest is 16 LSB bits + rest = val2 - cell0; + + y0 = LutTable[cell0] ; + y1 = LutTable[cell1] ; + + Output[0] = y0 + (y1 - y0) * rest; +} + + + +// Eval gray LUT having only one input channel +static +void Eval1Input(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p16) +{ + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, k1, rk, K0, K1; + int v; + cmsUInt32Number OutChan; + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + + v = Input[0] * p16 -> Domain[0]; + fk = _cmsToFixedDomain(v); + + k0 = FIXED_TO_INT(fk); + rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk); + + k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); + + K0 = p16 -> opta[0] * k0; + K1 = p16 -> opta[0] * k1; + + for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { + + Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); + } +} + + + +// Eval gray LUT having only one input channel +static +void Eval1InputFloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + cmsFloat32Number y1, y0; + cmsFloat32Number val2, rest; + int cell0, cell1; + cmsUInt32Number OutChan; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + + // if last value... + if (Value[0] == 1.0) { + Output[0] = LutTable[p -> Domain[0]]; + return; + } + + val2 = p -> Domain[0] * Value[0]; + + cell0 = (int) floor(val2); + cell1 = (int) ceil(val2); + + // Rest is 16 LSB bits + rest = val2 - cell0; + + cell0 *= p -> opta[0]; + cell1 *= p -> opta[0]; + + for (OutChan=0; OutChan < p->nOutputs; OutChan++) { + + y0 = LutTable[cell0 + OutChan] ; + y1 = LutTable[cell1 + OutChan] ; + + Output[OutChan] = y0 + (y1 - y0) * rest; + } +} + +// Bilinear interpolation (16 bits) - cmsFloat32Number version +static +void BilinearInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) + +{ +# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) +# define DENS(i,j) (LutTable[(i)+(j)+OutChan]) + + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + cmsFloat32Number px, py; + int x0, y0, + X0, Y0, X1, Y1; + int TotalOut, OutChan; + cmsFloat32Number fx, fy, + d00, d01, d10, d11, + dx0, dx1, + dxy; + + TotalOut = p -> nOutputs; + px = Input[0] * p->Domain[0]; + py = Input[1] * p->Domain[1]; + + x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; + y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; + + X0 = p -> opta[1] * x0; + X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[1]); + + Y0 = p -> opta[0] * y0; + Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d00 = DENS(X0, Y0); + d01 = DENS(X0, Y1); + d10 = DENS(X1, Y0); + d11 = DENS(X1, Y1); + + dx0 = LERP(fx, d00, d10); + dx1 = LERP(fx, d01, d11); + + dxy = LERP(fy, dx0, dx1); + + Output[OutChan] = dxy; + } + + +# undef LERP +# undef DENS +} + +// Bilinear interpolation (16 bits) - optimized version +static +void BilinearInterp16(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p) + +{ +#define DENS(i,j) (LutTable[(i)+(j)+OutChan]) +#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) + + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + int OutChan, TotalOut; + cmsS15Fixed16Number fx, fy; + register int rx, ry; + int x0, y0; + register int X0, X1, Y0, Y1; + int d00, d01, d10, d11, + dx0, dx1, + dxy; + + TotalOut = p -> nOutputs; + + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + x0 = FIXED_TO_INT(fx); + rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain + + + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + y0 = FIXED_TO_INT(fy); + ry = FIXED_REST_TO_INT(fy); + + + X0 = p -> opta[1] * x0; + X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]); + + Y0 = p -> opta[0] * y0; + Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d00 = DENS(X0, Y0); + d01 = DENS(X0, Y1); + d10 = DENS(X1, Y0); + d11 = DENS(X1, Y1); + + dx0 = LERP(rx, d00, d10); + dx1 = LERP(rx, d01, d11); + + dxy = LERP(ry, dx0, dx1); + + Output[OutChan] = (cmsUInt16Number) dxy; + } + + +# undef LERP +# undef DENS +} + + +// Trilinear interpolation (16 bits) - cmsFloat32Number version +static +void TrilinearInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) + +{ +# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) +# define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) + + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + cmsFloat32Number px, py, pz; + int x0, y0, z0, + X0, Y0, Z0, X1, Y1, Z1; + int TotalOut, OutChan; + cmsFloat32Number fx, fy, fz, + d000, d001, d010, d011, + d100, d101, d110, d111, + dx00, dx01, dx10, dx11, + dxy0, dxy1, dxyz; + + TotalOut = p -> nOutputs; + + // We need some clipping here + px = Input[0]; + py = Input[1]; + pz = Input[2]; + + if (px < 0) px = 0; + if (px > 1) px = 1; + if (py < 0) py = 0; + if (py > 1) py = 1; + if (pz < 0) pz = 0; + if (pz > 1) pz = 1; + + px *= p->Domain[0]; + py *= p->Domain[1]; + pz *= p->Domain[2]; + + x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; + y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; + z0 = (int) _cmsQuickFloor(pz); fz = pz - (cmsFloat32Number) z0; + + X0 = p -> opta[2] * x0; + X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d000 = DENS(X0, Y0, Z0); + d001 = DENS(X0, Y0, Z1); + d010 = DENS(X0, Y1, Z0); + d011 = DENS(X0, Y1, Z1); + + d100 = DENS(X1, Y0, Z0); + d101 = DENS(X1, Y0, Z1); + d110 = DENS(X1, Y1, Z0); + d111 = DENS(X1, Y1, Z1); + + + dx00 = LERP(fx, d000, d100); + dx01 = LERP(fx, d001, d101); + dx10 = LERP(fx, d010, d110); + dx11 = LERP(fx, d011, d111); + + dxy0 = LERP(fy, dx00, dx10); + dxy1 = LERP(fy, dx01, dx11); + + dxyz = LERP(fz, dxy0, dxy1); + + Output[OutChan] = dxyz; + } + + +# undef LERP +# undef DENS +} + +// Trilinear interpolation (16 bits) - optimized version +static +void TrilinearInterp16(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p) + +{ +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) + + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + int OutChan, TotalOut; + cmsS15Fixed16Number fx, fy, fz; + register int rx, ry, rz; + int x0, y0, z0; + register int X0, X1, Y0, Y1, Z0, Z1; + int d000, d001, d010, d011, + d100, d101, d110, d111, + dx00, dx01, dx10, dx11, + dxy0, dxy1, dxyz; + + TotalOut = p -> nOutputs; + + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + x0 = FIXED_TO_INT(fx); + rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain + + + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + y0 = FIXED_TO_INT(fy); + ry = FIXED_REST_TO_INT(fy); + + fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); + z0 = FIXED_TO_INT(fz); + rz = FIXED_REST_TO_INT(fz); + + + X0 = p -> opta[2] * x0; + X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d000 = DENS(X0, Y0, Z0); + d001 = DENS(X0, Y0, Z1); + d010 = DENS(X0, Y1, Z0); + d011 = DENS(X0, Y1, Z1); + + d100 = DENS(X1, Y0, Z0); + d101 = DENS(X1, Y0, Z1); + d110 = DENS(X1, Y1, Z0); + d111 = DENS(X1, Y1, Z1); + + + dx00 = LERP(rx, d000, d100); + dx01 = LERP(rx, d001, d101); + dx10 = LERP(rx, d010, d110); + dx11 = LERP(rx, d011, d111); + + dxy0 = LERP(ry, dx00, dx10); + dxy1 = LERP(ry, dx01, dx11); + + dxyz = LERP(rz, dxy0, dxy1); + + Output[OutChan] = (cmsUInt16Number) dxyz; + } + + +# undef LERP +# undef DENS +} + + +// Tetrahedral interpolation, using Sakamoto algorithm. +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +static +void TetrahedralInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number px, py, pz; + int x0, y0, z0, + X0, Y0, Z0, X1, Y1, Z1; + cmsFloat32Number rx, ry, rz; + cmsFloat32Number c0, c1=0, c2=0, c3=0; + int OutChan, TotalOut; + + TotalOut = p -> nOutputs; + + // We need some clipping here + px = Input[0]; + py = Input[1]; + pz = Input[2]; + + if (px < 0) px = 0; + if (px > 1) px = 1; + if (py < 0) py = 0; + if (py > 1) py = 1; + if (pz < 0) pz = 0; + if (pz > 1) pz = 1; + + px *= p->Domain[0]; + py *= p->Domain[1]; + pz *= p->Domain[2]; + + x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0); + y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0); + z0 = (int) _cmsQuickFloor(pz); rz = (pz - (cmsFloat32Number) z0); + + + X0 = p -> opta[2] * x0; + X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]); + + for (OutChan=0; OutChan < TotalOut; OutChan++) { + + // These are the 6 Tetrahedral + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz; + } + +} + +#undef DENS + + + +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) + +static +void TetrahedralInterp16(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table; + cmsS15Fixed16Number fx, fy, fz; + cmsS15Fixed16Number rx, ry, rz; + int x0, y0, z0; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsUInt32Number OutChan; + cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + cmsUInt32Number TotalOut = p -> nOutputs; + + + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); + + x0 = FIXED_TO_INT(fx); + y0 = FIXED_TO_INT(fy); + z0 = FIXED_TO_INT(fz); + + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); + rz = FIXED_REST_TO_INT(fz); + + X0 = p -> opta[2] * x0; + X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); + + // These are the 6 Tetrahedral + for (OutChan=0; OutChan < TotalOut; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Rest = c1 * rx + c2 * ry + c3 * rz; + + Output[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + } + +} +#undef DENS + + +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +static +void Eval4Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p16) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, rk; + int K0, K1; + cmsS15Fixed16Number fx, fy, fz; + cmsS15Fixed16Number rx, ry, rz; + int x0, y0, z0; + cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + cmsUInt32Number i; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsUInt32Number OutChan; + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + + + fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]); + fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]); + fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]); + fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]); + + k0 = FIXED_TO_INT(fk); + x0 = FIXED_TO_INT(fx); + y0 = FIXED_TO_INT(fy); + z0 = FIXED_TO_INT(fz); + + rk = FIXED_REST_TO_INT(fk); + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); + rz = FIXED_REST_TO_INT(fz); + + K0 = p16 -> opta[3] * k0; + K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]); + + X0 = p16 -> opta[2] * x0; + X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]); + + Y0 = p16 -> opta[1] * y0; + Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]); + + Z0 = p16 -> opta[0] * z0; + Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]); + + LutTable = (cmsUInt16Number*) p16 -> Table; + LutTable += K0; + + for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Rest = c1 * rx + c2 * ry + c3 * rz; + + Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + } + + + LutTable = (cmsUInt16Number*) p16 -> Table; + LutTable += K1; + + for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Rest = c1 * rx + c2 * ry + c3 * rz; + + Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + } + + + + for (i=0; i < p16 -> nOutputs; i++) { + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + } +} +#undef DENS + + +// For more that 3 inputs (i.e., CMYK) +// evaluate two 3-dimensional interpolations and then linearly interpolate between them. + + +static +void Eval4InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number rest; + cmsFloat32Number pk; + int k0, K0, K1; + const cmsFloat32Number* T; + cmsUInt32Number i; + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + + pk = Input[0] * p->Domain[0]; + k0 = _cmsQuickFloor(pk); + rest = pk - (cmsFloat32Number) k0; + + K0 = p -> opta[3] * k0; + K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[3]); + + p1 = *p; + memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + TetrahedralInterpFloat(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + TetrahedralInterpFloat(Input + 1, Tmp2, &p1); + + for (i=0; i < p -> nOutputs; i++) + { + cmsFloat32Number y0 = Tmp1[i]; + cmsFloat32Number y1 = Tmp2[i]; + + Output[i] = y0 + (y1 - y0) * rest; + } +} + + +static +void Eval5Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + + register const cmsInterpParams* p16) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, rk; + int K0, K1; + const cmsUInt16Number* T; + cmsUInt32Number i; + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); + k0 = FIXED_TO_INT(fk); + rk = FIXED_REST_TO_INT(fk); + + K0 = p16 -> opta[4] * k0; + K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); + + p1 = *p16; + memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval4Inputs(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval4Inputs(Input + 1, Tmp2, &p1); + + for (i=0; i < p16 -> nOutputs; i++) { + + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + } + +} + + +static +void Eval5InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number rest; + cmsFloat32Number pk; + int k0, K0, K1; + const cmsFloat32Number* T; + cmsUInt32Number i; + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + pk = Input[0] * p->Domain[0]; + k0 = _cmsQuickFloor(pk); + rest = pk - (cmsFloat32Number) k0; + + K0 = p -> opta[4] * k0; + K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[4]); + + p1 = *p; + memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval4InputsFloat(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval4InputsFloat(Input + 1, Tmp2, &p1); + + for (i=0; i < p -> nOutputs; i++) { + + cmsFloat32Number y0 = Tmp1[i]; + cmsFloat32Number y1 = Tmp2[i]; + + Output[i] = y0 + (y1 - y0) * rest; + } +} + + + +static +void Eval6Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p16) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, rk; + int K0, K1; + const cmsUInt16Number* T; + cmsUInt32Number i; + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); + k0 = FIXED_TO_INT(fk); + rk = FIXED_REST_TO_INT(fk); + + K0 = p16 -> opta[5] * k0; + K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); + + p1 = *p16; + memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval5Inputs(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval5Inputs(Input + 1, Tmp2, &p1); + + for (i=0; i < p16 -> nOutputs; i++) { + + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + } + +} + + +static +void Eval6InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number rest; + cmsFloat32Number pk; + int k0, K0, K1; + const cmsFloat32Number* T; + cmsUInt32Number i; + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + pk = Input[0] * p->Domain[0]; + k0 = _cmsQuickFloor(pk); + rest = pk - (cmsFloat32Number) k0; + + K0 = p -> opta[5] * k0; + K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[5]); + + p1 = *p; + memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval5InputsFloat(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval5InputsFloat(Input + 1, Tmp2, &p1); + + for (i=0; i < p -> nOutputs; i++) { + + cmsFloat32Number y0 = Tmp1[i]; + cmsFloat32Number y1 = Tmp2[i]; + + Output[i] = y0 + (y1 - y0) * rest; + } +} + + +static +void Eval7Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p16) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, rk; + int K0, K1; + const cmsUInt16Number* T; + cmsUInt32Number i; + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); + k0 = FIXED_TO_INT(fk); + rk = FIXED_REST_TO_INT(fk); + + K0 = p16 -> opta[6] * k0; + K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); + + p1 = *p16; + memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval6Inputs(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval6Inputs(Input + 1, Tmp2, &p1); + + for (i=0; i < p16 -> nOutputs; i++) { + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + } +} + + +static +void Eval7InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number rest; + cmsFloat32Number pk; + int k0, K0, K1; + const cmsFloat32Number* T; + cmsUInt32Number i; + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + pk = Input[0] * p->Domain[0]; + k0 = _cmsQuickFloor(pk); + rest = pk - (cmsFloat32Number) k0; + + K0 = p -> opta[6] * k0; + K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[6]); + + p1 = *p; + memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval6InputsFloat(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval6InputsFloat(Input + 1, Tmp2, &p1); + + + for (i=0; i < p -> nOutputs; i++) { + + cmsFloat32Number y0 = Tmp1[i]; + cmsFloat32Number y1 = Tmp2[i]; + + Output[i] = y0 + (y1 - y0) * rest; + + } +} + +static +void Eval8Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const cmsInterpParams* p16) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, rk; + int K0, K1; + const cmsUInt16Number* T; + cmsUInt32Number i; + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); + k0 = FIXED_TO_INT(fk); + rk = FIXED_REST_TO_INT(fk); + + K0 = p16 -> opta[7] * k0; + K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); + + p1 = *p16; + memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval7Inputs(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + Eval7Inputs(Input + 1, Tmp2, &p1); + + for (i=0; i < p16 -> nOutputs; i++) { + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + } +} + + + +static +void Eval8InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number rest; + cmsFloat32Number pk; + int k0, K0, K1; + const cmsFloat32Number* T; + cmsUInt32Number i; + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + pk = Input[0] * p->Domain[0]; + k0 = _cmsQuickFloor(pk); + rest = pk - (cmsFloat32Number) k0; + + K0 = p -> opta[7] * k0; + K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[7]); + + p1 = *p; + memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + Eval7InputsFloat(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + + Eval7InputsFloat(Input + 1, Tmp2, &p1); + + + for (i=0; i < p -> nOutputs; i++) { + + cmsFloat32Number y0 = Tmp1[i]; + cmsFloat32Number y1 = Tmp2[i]; + + Output[i] = y0 + (y1 - y0) * rest; + } +} + +// The default factory +static +cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags) +{ + + cmsInterpFunction Interpolation; + cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT); + cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR); + + memset(&Interpolation, 0, sizeof(Interpolation)); + + // Safety check + if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS) + return Interpolation; + + switch (nInputChannels) { + + case 1: // Gray LUT / linear + + if (nOutputChannels == 1) { + + if (IsFloat) + Interpolation.LerpFloat = LinLerp1Dfloat; + else + Interpolation.Lerp16 = LinLerp1D; + + } + else { + + if (IsFloat) + Interpolation.LerpFloat = Eval1InputFloat; + else + Interpolation.Lerp16 = Eval1Input; + } + break; + + case 2: // Duotone + if (IsFloat) + Interpolation.LerpFloat = BilinearInterpFloat; + else + Interpolation.Lerp16 = BilinearInterp16; + break; + + case 3: // RGB et al + + if (IsTrilinear) { + + if (IsFloat) + Interpolation.LerpFloat = TrilinearInterpFloat; + else + Interpolation.Lerp16 = TrilinearInterp16; + } + else { + + if (IsFloat) + Interpolation.LerpFloat = TetrahedralInterpFloat; + else { + + Interpolation.Lerp16 = TetrahedralInterp16; + } + } + break; + + case 4: // CMYK lut + + if (IsFloat) + Interpolation.LerpFloat = Eval4InputsFloat; + else + Interpolation.Lerp16 = Eval4Inputs; + break; + + case 5: // 5 Inks + if (IsFloat) + Interpolation.LerpFloat = Eval5InputsFloat; + else + Interpolation.Lerp16 = Eval5Inputs; + break; + + case 6: // 6 Inks + if (IsFloat) + Interpolation.LerpFloat = Eval6InputsFloat; + else + Interpolation.Lerp16 = Eval6Inputs; + break; + + case 7: // 7 inks + if (IsFloat) + Interpolation.LerpFloat = Eval7InputsFloat; + else + Interpolation.Lerp16 = Eval7Inputs; + break; + + case 8: // 8 inks + if (IsFloat) + Interpolation.LerpFloat = Eval8InputsFloat; + else + Interpolation.Lerp16 = Eval8Inputs; + break; + + break; + + default: + Interpolation.Lerp16 = NULL; + } + + return Interpolation; +} diff --git a/thirdparty/liblcms2/src/cmsio0.c b/thirdparty/liblcms2/src/cmsio0.c new file mode 100644 index 00000000..589ea6a3 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsio0.c @@ -0,0 +1,1720 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Generic I/O, tag dictionary management, profile struct + +// IOhandlers are abstractions used by littleCMS to read from whatever file, stream, +// memory block or any storage. Each IOhandler provides implementations for read, +// write, seek and tell functions. LittleCMS code deals with IO across those objects. +// In this way, is easier to add support for new storage media. + +// NULL stream, for taking care of used space ------------------------------------- + +// NULL IOhandler basically does nothing but keep track on how many bytes have been +// written. This is handy when creating profiles, where the file size is needed in the +// header. Then, whole profile is serialized across NULL IOhandler and a second pass +// writes the bytes to the pertinent IOhandler. + +typedef struct { + cmsUInt32Number Pointer; // Points to current location +} FILENULL; + +static +cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + cmsUInt32Number len = size * count; + ResData -> Pointer += len; + return count; + + cmsUNUSED_PARAMETER(Buffer); +} + +static +cmsBool NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + ResData ->Pointer = offset; + return TRUE; +} + +static +cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + return ResData -> Pointer; +} + +static +cmsBool NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Ptr) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + ResData ->Pointer += size; + if (ResData ->Pointer > iohandler->UsedSpace) + iohandler->UsedSpace = ResData ->Pointer; + + return TRUE; + + cmsUNUSED_PARAMETER(Ptr); +} + +static +cmsBool NULLClose(cmsIOHANDLER* iohandler) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + _cmsFree(iohandler ->ContextID, ResData); + _cmsFree(iohandler ->ContextID, iohandler); + return TRUE; +} + +// The NULL IOhandler creator +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) +{ + struct _cms_io_handler* iohandler = NULL; + FILENULL* fm = NULL; + + iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler)); + if (iohandler == NULL) return NULL; + + fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL)); + if (fm == NULL) goto Error; + + fm ->Pointer = 0; + + iohandler ->ContextID = ContextID; + iohandler ->stream = (void*) fm; + iohandler ->UsedSpace = 0; + iohandler ->ReportedSize = 0; + iohandler ->PhysicalFile[0] = 0; + + iohandler ->Read = NULLRead; + iohandler ->Seek = NULLSeek; + iohandler ->Close = NULLClose; + iohandler ->Tell = NULLTell; + iohandler ->Write = NULLWrite; + + return iohandler; + +Error: + if (fm) _cmsFree(ContextID, fm); + if (iohandler) _cmsFree(ContextID, iohandler); + return NULL; + +} + + +// Memory-based stream -------------------------------------------------------------- + +// Those functions implements an iohandler which takes a block of memory as storage medium. + +typedef struct { + cmsUInt8Number* Block; // Points to allocated memory + cmsUInt32Number Size; // Size of allocated memory + cmsUInt32Number Pointer; // Points to current location + int FreeBlockOnClose; // As title + +} FILEMEM; + +static +cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + cmsUInt8Number* Ptr; + cmsUInt32Number len = size * count; + + if (ResData -> Pointer + len > ResData -> Size){ + + len = (ResData -> Size - ResData -> Pointer); + cmsSignalError(iohandler ->ContextID, cmsERROR_READ, "Read from memory error. Got %d bytes, block should be of %d bytes", len, count * size); + return 0; + } + + Ptr = ResData -> Block; + Ptr += ResData -> Pointer; + memmove(Buffer, Ptr, len); + ResData -> Pointer += len; + + return count; +} + +// SEEK_CUR is assumed +static +cmsBool MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (offset > ResData ->Size) { + cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); + return FALSE; + } + + ResData ->Pointer = offset; + return TRUE; +} + +// Tell for memory +static +cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (ResData == NULL) return 0; + return ResData -> Pointer; +} + + +// Writes data to memory, also keeps used space for further reference. +static +cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (ResData == NULL) return FALSE; // Housekeeping + + if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing + + memmove(ResData ->Block + ResData ->Pointer, Ptr, size); + ResData ->Pointer += size; + + if (ResData ->Pointer > iohandler->UsedSpace) + iohandler->UsedSpace = ResData ->Pointer; + + + iohandler->UsedSpace += size; + + return TRUE; +} + + +static +cmsBool MemoryClose(struct _cms_io_handler* iohandler) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (ResData ->FreeBlockOnClose) { + + if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block); + } + + _cmsFree(iohandler ->ContextID, ResData); + _cmsFree(iohandler ->ContextID, iohandler); + + return TRUE; +} + +// Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes +// a copy of the memory block for letting user to free the memory after invoking open profile. In write +// mode ("w"), Buffere points to the begin of memory block to be written. +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode) +{ + cmsIOHANDLER* iohandler = NULL; + FILEMEM* fm = NULL; + + _cmsAssert(AccessMode != NULL); + + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); + if (iohandler == NULL) return NULL; + + switch (*AccessMode) { + + case 'r': + fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); + if (fm == NULL) goto Error; + + if (Buffer == NULL) { + cmsSignalError(ContextID, cmsERROR_READ, "Couldn't read profile from NULL pointer"); + goto Error; + } + + fm ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, size); + if (fm ->Block == NULL) { + + _cmsFree(ContextID, fm); + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", size); + return NULL; + } + + + memmove(fm->Block, Buffer, size); + fm ->FreeBlockOnClose = TRUE; + fm ->Size = size; + fm ->Pointer = 0; + iohandler -> ReportedSize = size; + break; + + case 'w': + fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); + if (fm == NULL) goto Error; + + fm ->Block = (cmsUInt8Number*) Buffer; + fm ->FreeBlockOnClose = FALSE; + fm ->Size = size; + fm ->Pointer = 0; + iohandler -> ReportedSize = 0; + break; + + default: + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown access mode '%c'", *AccessMode); + return NULL; + } + + iohandler ->ContextID = ContextID; + iohandler ->stream = (void*) fm; + iohandler ->UsedSpace = 0; + iohandler ->PhysicalFile[0] = 0; + + iohandler ->Read = MemoryRead; + iohandler ->Seek = MemorySeek; + iohandler ->Close = MemoryClose; + iohandler ->Tell = MemoryTell; + iohandler ->Write = MemoryWrite; + + return iohandler; + +Error: + if (fm) _cmsFree(ContextID, fm); + if (iohandler) _cmsFree(ContextID, iohandler); + return NULL; +} + +// File-based stream ------------------------------------------------------- + +// Read count elements of size bytes each. Return number of elements read +static +cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) +{ + cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream); + + if (nReaded != count) { + cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); + return 0; + } + + return nReaded; +} + +// Postion file pointer in the file +static +cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) +{ + if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) { + + cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file"); + return FALSE; + } + + return TRUE; +} + +// Returns file pointer position +static +cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) +{ + return ftell((FILE*)iohandler ->stream); +} + +// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error +static +cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer) +{ + if (size == 0) return TRUE; // We allow to write 0 bytes, but nothing is written + + iohandler->UsedSpace += size; + return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1); +} + +// Closes the file +static +cmsBool FileClose(cmsIOHANDLER* iohandler) +{ + if (fclose((FILE*) iohandler ->stream) != 0) return FALSE; + _cmsFree(iohandler ->ContextID, iohandler); + return TRUE; +} + +// Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set +// to NULL and no real writting is performed. This only happens in writting access mode +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) +{ + cmsIOHANDLER* iohandler = NULL; + FILE* fm = NULL; + + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); + if (iohandler == NULL) return NULL; + + switch (*AccessMode) { + + case 'r': + fm = fopen(FileName, "rb"); + if (fm == NULL) { + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); + return NULL; + } + iohandler -> ReportedSize = cmsfilelength(fm); + break; + + case 'w': + fm = fopen(FileName, "wb"); + if (fm == NULL) { + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName); + return NULL; + } + iohandler -> ReportedSize = 0; + break; + + default: + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode); + return NULL; + } + + iohandler ->ContextID = ContextID; + iohandler ->stream = (void*) fm; + iohandler ->UsedSpace = 0; + + // Keep track of the original file + if (FileName != NULL) { + + strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); + iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; + } + + iohandler ->Read = FileRead; + iohandler ->Seek = FileSeek; + iohandler ->Close = FileClose; + iohandler ->Tell = FileTell; + iohandler ->Write = FileWrite; + + return iohandler; +} + +// Create a iohandler for stream based files +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream) +{ + cmsIOHANDLER* iohandler = NULL; + + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); + if (iohandler == NULL) return NULL; + + iohandler -> ContextID = ContextID; + iohandler -> stream = (void*) Stream; + iohandler -> UsedSpace = 0; + iohandler -> ReportedSize = cmsfilelength(Stream); + iohandler -> PhysicalFile[0] = 0; + + iohandler ->Read = FileRead; + iohandler ->Seek = FileSeek; + iohandler ->Close = FileClose; + iohandler ->Tell = FileTell; + iohandler ->Write = FileWrite; + + return iohandler; +} + + + +// Close an open IO handler +cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io) +{ + return io -> Close(io); +} + +// ------------------------------------------------------------------------------------------------------- + +// Creates an empty structure holding all required parameters +cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) +{ + time_t now = time(NULL); + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE)); + if (Icc == NULL) return NULL; + + Icc ->ContextID = ContextID; + + // Set it to empty + Icc -> TagCount = 0; + + // Set default version + Icc ->Version = 0x02100000; + + // Set creation date/time + memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + + // Return the handle + return (cmsHPROFILE) Icc; +} + +cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + + if (Icc == NULL) return NULL; + return Icc -> ContextID; +} + + +// Return the number of tags +cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + if (Icc == NULL) return -1; + + return Icc->TagCount; +} + +// Return the tag signature of a given tag number +cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + + if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available + if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check + + return Icc ->TagNames[n]; +} + + +static +int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig) +{ + cmsUInt32Number i; + + for (i=0; i < Profile -> TagCount; i++) { + + if (sig == Profile -> TagNames[i]) + return i; + } + + return -1; +} + +// Search for a specific tag in tag dictionary. Returns position or -1 if tag not found. +// If followlinks is turned on, then the position of the linked tag is returned +int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks) +{ + int n; + cmsTagSignature LinkedSig; + + do { + + // Search for given tag in ICC profile directory + n = SearchOneTag(Icc, sig); + if (n < 0) + return -1; // Not found + + if (!lFollowLinks) + return n; // Found, don't follow links + + // Is this a linked tag? + LinkedSig = Icc ->TagLinked[n]; + + // Yes, follow link + if (LinkedSig != (cmsTagSignature) 0) { + sig = LinkedSig; + } + + } while (LinkedSig != (cmsTagSignature) 0); + + return n; +} + + +// Create a new tag entry + +static +cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) +{ + int i; + + // Search for the tag + i = _cmsSearchTag(Icc, sig, FALSE); + + // Now let's do it easy. If the tag has been already written, that's an error + if (i >= 0) { + cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig); + return FALSE; + } + else { + + // New one + + if (Icc -> TagCount >= MAX_TABLE_TAG) { + cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); + return FALSE; + } + + *NewPos = Icc ->TagCount; + Icc -> TagCount++; + } + + return TRUE; +} + + +// Check existance +cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) (void*) hProfile; + return _cmsSearchTag(Icc, sig, FALSE) >= 0; +} + + +// Read profile header and validate it +cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) +{ + cmsTagEntry Tag; + cmsICCHeader Header; + cmsUInt32Number i, j; + cmsUInt32Number HeaderSize; + cmsIOHANDLER* io = Icc ->IOhandler; + cmsUInt32Number TagCount; + + + // Read the header + if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { + return FALSE; + } + + // Validate file as an ICC profile + if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) { + cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature"); + return FALSE; + } + + // Adjust endianess of the used parameters + Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); + Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); + Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); + Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); + Icc -> flags = _cmsAdjustEndianess32(Header.flags); + Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); + Icc -> model = _cmsAdjustEndianess32(Header.model); + _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes); + Icc -> Version = _cmsAdjustEndianess32(Header.version); + + // Get size as reported in header + HeaderSize = _cmsAdjustEndianess32(Header.size); + + // Make sure HeaderSize is lower than profile size + if (HeaderSize >= Icc ->IOhandler ->ReportedSize) + HeaderSize = Icc ->IOhandler ->ReportedSize; + + + // Get creation date/time + _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created); + + // The profile ID are 32 raw bytes + memmove(Icc ->ProfileID.ID32, Header.profileID.ID32, 16); + + + // Read tag directory + if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; + if (TagCount > MAX_TABLE_TAG) { + + cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount); + return FALSE; + } + + + // Read tag directory + Icc -> TagCount = 0; + for (i=0; i < TagCount; i++) { + + if (!_cmsReadUInt32Number(io, (cmsUInt32Number *) &Tag.sig)) return FALSE; + if (!_cmsReadUInt32Number(io, &Tag.offset)) return FALSE; + if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE; + + // Perform some sanity check. Offset + size should fall inside file. + if (Tag.offset + Tag.size > HeaderSize || + Tag.offset + Tag.size < Tag.offset) + continue; + + Icc -> TagNames[Icc ->TagCount] = Tag.sig; + Icc -> TagOffsets[Icc ->TagCount] = Tag.offset; + Icc -> TagSizes[Icc ->TagCount] = Tag.size; + + // Search for links + for (j=0; j < Icc ->TagCount; j++) { + + if ((Icc ->TagOffsets[j] == Tag.offset) && + (Icc ->TagSizes[j] == Tag.size)) { + + Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; + } + + } + + Icc ->TagCount++; + } + + return TRUE; +} + +// Saves profile header +cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) +{ + cmsICCHeader Header; + cmsUInt32Number i; + cmsTagEntry Tag; + cmsInt32Number Count = 0; + + Header.size = _cmsAdjustEndianess32(UsedSpace); + Header.cmmId = _cmsAdjustEndianess32(lcmsSignature); + Header.version = _cmsAdjustEndianess32(Icc ->Version); + + Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass); + Header.colorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> ColorSpace); + Header.pcs = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> PCS); + + // NOTE: in v4 Timestamp must be in UTC rather than in local time + _cmsEncodeDateTimeNumber(&Header.date, &Icc ->Created); + + Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); + +#ifdef CMS_IS_WINDOWS_ + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); +#else + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); +#endif + + Header.flags = _cmsAdjustEndianess32(Icc -> flags); + Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); + Header.model = _cmsAdjustEndianess32(Icc -> model); + + _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes); + + // Rendering intent in the header (for embedded profiles) + Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent); + + // Illuminant is always D50 + Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X)); + Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y)); + Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z)); + + // Created by LittleCMS (that's me!) + Header.creator = _cmsAdjustEndianess32(lcmsSignature); + + memset(&Header.reserved, 0, sizeof(Header.reserved)); + + // Set profile ID. Endianess is always big endian + memmove(&Header.profileID, &Icc ->ProfileID, 16); + + // Dump the header + if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE; + + // Saves Tag directory + + // Get true count + for (i=0; i < Icc -> TagCount; i++) { + if (Icc ->TagNames[i] != 0) + Count++; + } + + // Store number of tags + if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; + + for (i=0; i < Icc -> TagCount; i++) { + + if (Icc ->TagNames[i] == 0) continue; // It is just a placeholder + + Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]); + Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]); + Tag.size = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]); + + if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- Set/Get several struct members + + +cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> RenderingIntent; +} + +void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> RenderingIntent = RenderingIntent; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return (cmsUInt32Number) Icc -> flags; +} + +void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> flags = (cmsUInt32Number) Flags; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return (cmsUInt32Number) Icc ->manufacturer; +} + +void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> manufacturer = (cmsUInt32Number) manufacturer; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return (cmsUInt32Number) Icc ->model; +} + +void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> manufacturer = (cmsUInt32Number) model; +} + + +void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(Flags, &Icc -> attributes, sizeof(cmsUInt64Number)); +} + +void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(&Icc -> attributes, &Flags, sizeof(cmsUInt64Number)); +} + +void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(ProfileID, Icc ->ProfileID.ID8, 16); +} + +void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(&Icc -> ProfileID, ProfileID, 16); +} + +cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(Dest, &Icc ->Created, sizeof(struct tm)); + return TRUE; +} + +cmsColorSpaceSignature CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> PCS; +} + +void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> PCS = pcs; +} + +cmsColorSpaceSignature CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> ColorSpace; +} + +void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> ColorSpace = sig; +} + +cmsProfileClassSignature CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> DeviceClass; +} + +void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> DeviceClass = sig; +} + +cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> Version; +} + +void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> Version = Version; +} + +// Get an hexadecimal number with same digits as v +static +cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut) +{ + char Buff[100]; + int i, len; + cmsUInt32Number out; + + for (len=0; in > 0 && len < 100; len++) { + + Buff[len] = (char) (in % BaseIn); + in /= BaseIn; + } + + for (i=len-1, out=0; i >= 0; --i) { + out = out * BaseOut + Buff[i]; + } + + return out; +} + +void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + + // 4.2 -> 0x4200000 + + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16; +} + +cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsUInt32Number n = Icc -> Version >> 16; + + return BaseToBase(n, 16, 10) / 100.0; +} +// -------------------------------------------------------------------------------------------------------------- + + +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + +// Create profile from disk file +cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = cmsOpenIOhandlerFromFile(ContextID, lpFileName, sAccess); + if (NewIcc ->IOhandler == NULL) goto Error; + + if (*sAccess == 'W' || *sAccess == 'w') { + + NewIcc -> IsWrite = TRUE; + + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess) +{ + return cmsOpenProfileFromFileTHR(NULL, ICCProfile, sAccess); +} + + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char *sAccess) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = cmsOpenIOhandlerFromStream(ContextID, ICCProfile); + if (NewIcc ->IOhandler == NULL) goto Error; + + if (*sAccess == 'w') { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; + +} + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char *sAccess) +{ + return cmsOpenProfileFromStreamTHR(NULL, ICCProfile, sAccess); +} + + +// Open from memory block +cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* MemPtr, cmsUInt32Number dwSize) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty; + + hEmpty = cmsCreateProfilePlaceholder(ContextID); + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + // Ok, in this case const void* is casted to void* just because open IO handler + // shares read and writting modes. Don't abuse this feature! + NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r"); + if (NewIcc ->IOhandler == NULL) goto Error; + + if (!_cmsReadHeader(NewIcc)) goto Error; + + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number dwSize) +{ + return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize); +} + + + +// Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig +static +cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) +{ + cmsUInt8Number* Data; + cmsUInt32Number i; + cmsUInt32Number Begin; + cmsIOHANDLER* io = Icc ->IOhandler; + cmsTagDescriptor* TagDescriptor; + cmsTagTypeSignature TypeBase; + cmsTagTypeHandler* TypeHandler; + + + for (i=0; i < Icc -> TagCount; i++) { + + + if (Icc ->TagNames[i] == 0) continue; + + // Linked tags are not written + if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue; + + Icc -> TagOffsets[i] = Begin = io ->UsedSpace; + + Data = (cmsUInt8Number*) Icc -> TagPtrs[i]; + + if (!Data) { + + // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. + // In this case a blind copy of the block data is performed + if (FileOrig != NULL && Icc -> TagOffsets[i]) { + + cmsUInt32Number TagSize = FileOrig -> TagSizes[i]; + cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i]; + void* Mem; + + if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE; + + Mem = _cmsMalloc(Icc ->ContextID, TagSize); + if (Mem == NULL) return FALSE; + + if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE; + if (!io ->Write(io, TagSize, Mem)) return FALSE; + _cmsFree(Icc ->ContextID, Mem); + + Icc -> TagSizes[i] = (io ->UsedSpace - Begin); + + + // Align to 32 bit boundary. + if (! _cmsWriteAlignment(io)) + return FALSE; + } + + continue; + } + + + // Should this tag be saved as RAW? If so, tagsizes should be specified in advance (no further cooking is done) + if (Icc ->TagSaveAsRaw[i]) { + + if (io -> Write(io, Icc ->TagSizes[i], Data) != 1) return FALSE; + } + else { + + // Search for support on this tag + TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); + if (TagDescriptor == NULL) continue; // Unsupported, ignore it + + TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler == NULL) { + cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); + continue; + } + + TypeBase = TypeHandler ->Signature; + if (!_cmsWriteTypeBase(io, TypeBase)) + return FALSE; + + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; + if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) { + + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); + cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String); + return FALSE; + } + } + + + Icc -> TagSizes[i] = (io ->UsedSpace - Begin); + + // Align to 32 bit boundary. + if (! _cmsWriteAlignment(io)) + return FALSE; + } + + + return TRUE; +} + + +// Fill the offset and size fields for all linked tags +static +cmsBool SetLinks( _cmsICCPROFILE* Icc) +{ + cmsUInt32Number i; + + for (i=0; i < Icc -> TagCount; i++) { + + cmsTagSignature lnk = Icc ->TagLinked[i]; + if (lnk != (cmsTagSignature) 0) { + + int j = _cmsSearchTag(Icc, lnk, FALSE); + if (j >= 0) { + + Icc ->TagOffsets[i] = Icc ->TagOffsets[j]; + Icc ->TagSizes[i] = Icc ->TagSizes[j]; + } + + } + } + + return TRUE; +} + +// Low-level save to IOHANDLER. It returns the number of bytes used to +// store the profile, or zero on error. io may be NULL and in this case +// no data is written--only sizes are calculated +cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE Keep; + cmsIOHANDLER* PrevIO; + cmsUInt32Number UsedSpace; + cmsContext ContextID; + + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); + + ContextID = cmsGetProfileContextID(hProfile); + PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID); + if (PrevIO == NULL) return 0; + + // Pass #1 does compute offsets + + if (!_cmsWriteHeader(Icc, 0)) return 0; + if (!SaveTags(Icc, &Keep)) return 0; + + UsedSpace = PrevIO ->UsedSpace; + + // Pass #2 does save to iohandler + + if (io != NULL) { + Icc ->IOhandler = io; + if (!SetLinks(Icc)) goto CleanUp; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp; + if (!SaveTags(Icc, &Keep)) goto CleanUp; + } + + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + if (!cmsCloseIOhandler(PrevIO)) return 0; + + return UsedSpace; + + +CleanUp: + cmsCloseIOhandler(PrevIO); + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + return 0; +} + + +// Low-level save to disk. +cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w"); + cmsBool rc; + + if (io == NULL) return FALSE; + + rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); + rc &= cmsCloseIOhandler(io); + + if (rc == FALSE) { // remove() is C99 per 7.19.4.1 + remove(FileName); // We have to IGNORE return value in this case + } + return rc; +} + +// Same as anterior, but for streams +cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream) +{ + cmsBool rc; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream); + + if (io == NULL) return FALSE; + + rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); + rc &= cmsCloseIOhandler(io); + + return rc; +} + + +// Same as anterior, but for memory blocks. In this case, a NULL as MemPtr means calculate needed space only +cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded) +{ + cmsBool rc; + cmsIOHANDLER* io; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // Should we just calculate the needed space? + if (MemPtr == NULL) { + + *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); + return TRUE; + } + + // That is a real write operation + io = cmsOpenIOhandlerFromMem(ContextID, MemPtr, *BytesNeeded, "w"); + if (io == NULL) return FALSE; + + rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); + rc &= cmsCloseIOhandler(io); + + return rc; +} + + + +// Closes a profile freeing any involved resources +cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsBool rc = TRUE; + cmsUInt32Number i; + + if (!Icc) return FALSE; + + // Was open in write mode? + if (Icc ->IsWrite) { + + Icc ->IsWrite = FALSE; // Assure no further writting + rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); + } + + for (i=0; i < Icc -> TagCount; i++) { + + if (Icc -> TagPtrs[i]) { + + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameters + TypeHandler ->ICCVersion = Icc ->Version; + TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + } + else + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + } + + if (Icc ->IOhandler != NULL) { + rc &= cmsCloseIOhandler(Icc->IOhandler); + } + + _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory + + return rc; +} + + +// ------------------------------------------------------------------------------------------------------------------- + + +// Returns TRUE if a given tag is supported by a plug-in +static +cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Type) +{ + cmsUInt32Number i, nMaxTypes; + + nMaxTypes = TagDescriptor->nSupportedTypes; + if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN) + nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN; + + for (i=0; i < nMaxTypes; i++) { + if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; + } + + return FALSE; +} + + +// That's the main read function +void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsIOHANDLER* io = Icc ->IOhandler; + cmsTagTypeHandler* TypeHandler; + cmsTagDescriptor* TagDescriptor; + cmsTagTypeSignature BaseType; + cmsUInt32Number Offset, TagSize; + cmsUInt32Number ElemCount; + int n; + + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) return NULL; // Not found, return NULL + + + + // If the element is already in memory, return the pointer + if (Icc -> TagPtrs[n]) { + + if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked + return Icc -> TagPtrs[n]; + } + + // We need to read it. Get the offset and size to the file + Offset = Icc -> TagOffsets[n]; + TagSize = Icc -> TagSizes[n]; + + // Seek to its location + if (!io -> Seek(io, Offset)) + return NULL; + + // Search for support on this tag + TagDescriptor = _cmsGetTagDescriptor(sig); + if (TagDescriptor == NULL) return NULL; // Unsupported. + + // if supported, get type and check if in list + BaseType = _cmsReadTypeBase(io); + if (BaseType == 0) return NULL; + + if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL; + + TagSize -= 8; // Alredy read by the type base logic + + // Get type handler + TypeHandler = _cmsGetTagTypeHandler(BaseType); + if (TypeHandler == NULL) return NULL; + + + // Read the tag + Icc -> TagTypeHandlers[n] = TypeHandler; + + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; + Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize); + + // The tag type is supported, but something wrong happend and we cannot read the tag. + // let know the user about this (although it is just a warning) + if (Icc -> TagPtrs[n] == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); + return NULL; + } + + // This is a weird error that may be a symptom of something more serious, the number of + // stored item is actually less than the number of required elements. + if (ElemCount < TagDescriptor ->ElemCount) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", + String, TagDescriptor ->ElemCount, ElemCount); + } + + + // Return the data + return Icc -> TagPtrs[n]; +} + + +// Get true type of data +cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsTagTypeHandler* TypeHandler; + int n; + + // Search for given tag in ICC profile directory + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL + + // Get the handler. The true type is there + TypeHandler = Icc -> TagTypeHandlers[n]; + return TypeHandler ->Signature; +} + + +// Write a single tag. This just keeps track of the tak into a list of "to be written". If the tag is already +// in that list, the previous version is deleted. +cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsTagTypeHandler* TypeHandler = NULL; + cmsTagDescriptor* TagDescriptor = NULL; + cmsTagTypeSignature Type; + int i; + cmsFloat64Number Version; + char TypeString[5], SigString[5]; + + + if (data == NULL) { + + cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag"); + return FALSE; + } + + i = _cmsSearchTag(Icc, sig, FALSE); + if (i >=0) { + + if (Icc -> TagPtrs[i] != NULL) { + + // Already exists. Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameter + TypeHandler ->ICCVersion = Icc ->Version; + TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + } + } + } + } + else { + // New one + i = Icc -> TagCount; + + if (i >= MAX_TABLE_TAG) { + cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); + return FALSE; + } + + Icc -> TagCount++; + } + + // This is not raw + Icc ->TagSaveAsRaw[i] = FALSE; + + // This is not a link + Icc ->TagLinked[i] = (cmsTagSignature) 0; + + // Get information about the TAG. + TagDescriptor = _cmsGetTagDescriptor(sig); + if (TagDescriptor == NULL){ + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); + return FALSE; + } + + + // Now we need to know which type to use. It depends on the version. + Version = cmsGetProfileVersion(hProfile); + + if (TagDescriptor ->DecideType != NULL) { + + // Let the tag descriptor to decide the type base on depending on + // the data. This is useful for example on parametric curves, where + // curves specified by a table cannot be saved as parametric and needs + // to be revented to single v2-curves, even on v4 profiles. + + Type = TagDescriptor ->DecideType(Version, data); + } + else { + + + Type = TagDescriptor ->SupportedTypes[0]; + } + + // Does the tag support this type? + if (!IsTypeSupported(TagDescriptor, Type)) { + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); + return FALSE; + } + + // Does we have a handler for this type? + TypeHandler = _cmsGetTagTypeHandler(Type); + if (TypeHandler == NULL) { + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); + return FALSE; // Should never happen + } + + + // Fill fields on icc structure + Icc ->TagTypeHandlers[i] = TypeHandler; + Icc ->TagNames[i] = sig; + Icc ->TagSizes[i] = 0; + Icc ->TagOffsets[i] = 0; + + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; + Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); + + if (Icc ->TagPtrs[i] == NULL) { + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); + + return FALSE; + } + + return TRUE; +} + +// Read and write raw data. The only way those function would work and keep consistence with normal read and write +// is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained +// data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where +// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows +// to write a tag as raw data and the read it as handled. + +cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + void *Object; + int i; + cmsIOHANDLER* MemIO; + cmsTagTypeHandler* TypeHandler = NULL; + cmsTagDescriptor* TagDescriptor = NULL; + cmsUInt32Number rc; + cmsUInt32Number Offset, TagSize; + + // Search for given tag in ICC profile directory + i = _cmsSearchTag(Icc, sig, TRUE); + if (i < 0) return 0; // Not found, return 0 + + // It is already read? + if (Icc -> TagPtrs[i] == NULL) { + + // No yet, get original position + Offset = Icc ->TagOffsets[i]; + TagSize = Icc ->TagSizes[i]; + + + // read the data directly, don't keep copy + if (data != NULL) { + + if (BufferSize < TagSize) + TagSize = BufferSize; + + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; + } + + return Icc ->TagSizes[i]; + } + + // The data has been already read, or written. But wait!, maybe the user choosed to save as + // raw data. In this case, return the raw data directly + if (Icc ->TagSaveAsRaw[i]) { + + if (data != NULL) { + + TagSize = Icc ->TagSizes[i]; + if (BufferSize < TagSize) + TagSize = BufferSize; + + memmove(data, Icc ->TagPtrs[i], TagSize); + } + + return Icc ->TagSizes[i]; + } + + // Already readed, or previously set by cmsWriteTag(). We need to serialize that + // data to raw in order to maintain consistency. + Object = cmsReadTag(hProfile, sig); + if (Object == NULL) return 0; + + // Now we need to serialize to a memory block: just use a memory iohandler + + if (data == NULL) { + MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); + } else{ + MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); + } + if (MemIO == NULL) return 0; + + // Obtain type handling for the tag + TypeHandler = Icc ->TagTypeHandlers[i]; + TagDescriptor = _cmsGetTagDescriptor(sig); + + // Serialize + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; + if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0; + + // Get Size and close + rc = MemIO ->Tell(MemIO); + cmsCloseIOhandler(MemIO); // Ignore return code this time + + return rc; +} + +// Similar to the anterior. This function allows to write directly to the ICC profile any data, without +// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading +// it as cooked without serializing does result into an error. If that is wha you want, you will need to dump +// the profile to memry or disk and then reopen it. +cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + int i; + + if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + + // Mark the tag as being written as RAW + Icc ->TagSaveAsRaw[i] = TRUE; + Icc ->TagNames[i] = sig; + Icc ->TagLinked[i] = (cmsTagSignature) 0; + + // Keep a copy of the block + Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); + Icc ->TagSizes[i] = Size; + + return TRUE; +} + +// Using this function you can collapse several tag entries to the same block in the profile +cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + int i; + + if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + + // Keep necessary information + Icc ->TagSaveAsRaw[i] = FALSE; + Icc ->TagNames[i] = sig; + Icc ->TagLinked[i] = dest; + + Icc ->TagPtrs[i] = NULL; + Icc ->TagSizes[i] = 0; + Icc ->TagOffsets[i] = 0; + + return TRUE; +} + + +// Returns the tag linked to sig, in the case two tags are sharing same resource +cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + int i; + + // Search for given tag in ICC profile directory + i = _cmsSearchTag(Icc, sig, FALSE); + if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 + + return Icc -> TagLinked[i]; +} diff --git a/thirdparty/liblcms2/src/cmsio1.c b/thirdparty/liblcms2/src/cmsio1.c new file mode 100644 index 00000000..c93eaa80 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsio1.c @@ -0,0 +1,760 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Read tags using low-level functions, provides necessary glue code to adapt versions, etc. + +// LUT tags +static const cmsTagSignature Device2PCS16[] = {cmsSigAToB0Tag, // Perceptual + cmsSigAToB1Tag, // Relative colorimetric + cmsSigAToB2Tag, // Saturation + cmsSigAToB1Tag }; // Absolute colorimetric + +static const cmsTagSignature Device2PCSFloat[] = {cmsSigDToB0Tag, // Perceptual + cmsSigDToB1Tag, // Relative colorimetric + cmsSigDToB2Tag, // Saturation + cmsSigDToB3Tag }; // Absolute colorimetric + +static const cmsTagSignature PCS2Device16[] = {cmsSigBToA0Tag, // Perceptual + cmsSigBToA1Tag, // Relative colorimetric + cmsSigBToA2Tag, // Saturation + cmsSigBToA1Tag }; // Absolute colorimetric + +static const cmsTagSignature PCS2DeviceFloat[] = {cmsSigBToD0Tag, // Perceptual + cmsSigBToD1Tag, // Relative colorimetric + cmsSigBToD2Tag, // Saturation + cmsSigBToD3Tag }; // Absolute colorimetric + + +// Factors to convert from 1.15 fixed point to 0..1.0 range and vice-versa +#define InpAdj (1.0/MAX_ENCODEABLE_XYZ) // (65536.0/(65535.0*2.0)) +#define OutpAdj (MAX_ENCODEABLE_XYZ) // ((2.0*65535.0)/65536.0) + +// Several resources for gray conversions. +static const cmsFloat64Number GrayInputMatrix[] = { (InpAdj*cmsD50X), (InpAdj*cmsD50Y), (InpAdj*cmsD50Z) }; +static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 }; +static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 }; +static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 }; + +// Get a media white point fixing some issues found in certain old profiles +cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile) +{ + cmsCIEXYZ* Tag; + + _cmsAssert(Dest != NULL); + + Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); + + // If no wp, take D50 + if (Tag == NULL) { + *Dest = *cmsD50_XYZ(); + return TRUE; + } + + // V2 display profiles should give D50 + if (cmsGetEncodedICCversion(hProfile) < 0x4000000) { + + if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { + *Dest = *cmsD50_XYZ(); + return TRUE; + } + } + + // All seems ok + *Dest = *Tag; + return TRUE; +} + + +// Chromatic adaptation matrix. Fix some issues as well +cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) +{ + cmsMAT3* Tag; + + _cmsAssert(Dest != NULL); + + Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag); + + if (Tag != NULL) { + + *Dest = *Tag; + return TRUE; + } + + // No CHAD available, default it to identity + _cmsMAT3identity(Dest); + + // V2 display profiles should give D50 + if (cmsGetEncodedICCversion(hProfile) < 0x4000000) { + + if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { + + cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); + + if (White == NULL) { + + _cmsMAT3identity(Dest); + return TRUE; + } + + return _cmsAdaptationMatrix(Dest, NULL, cmsD50_XYZ(), White); + } + } + + return TRUE; +} + + +// Auxiliar, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper +static +cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile) +{ + cmsCIEXYZ *PtrRed, *PtrGreen, *PtrBlue; + + _cmsAssert(r != NULL); + + PtrRed = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigRedColorantTag); + PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag); + PtrBlue = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag); + + if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL) + return FALSE; + + _cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X, PtrBlue -> X); + _cmsVEC3init(&r -> v[1], PtrRed -> Y, PtrGreen -> Y, PtrBlue -> Y); + _cmsVEC3init(&r -> v[2], PtrRed -> Z, PtrGreen -> Z, PtrBlue -> Z); + + return TRUE; +} + + +// Gray input pipeline +static +cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) +{ + cmsToneCurve *GrayTRC; + cmsPipeline* Lut; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); + if (GrayTRC == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 1, 3); + if (Lut == NULL) return NULL; + + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + // In this case we implement the profile as an identity matrix plus 3 tone curves + cmsUInt16Number Zero[2] = { 0x8080, 0x8080 }; + cmsToneCurve* EmptyTab; + cmsToneCurve* LabCurves[3]; + + EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); + + if (EmptyTab == NULL) { + + cmsPipelineFree(Lut); + return NULL; + } + + LabCurves[0] = GrayTRC; + LabCurves[1] = EmptyTab; + LabCurves[2] = EmptyTab; + + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)); + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves)); + + cmsFreeToneCurve(EmptyTab); + + } + else { + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)); + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL)); + } + + return Lut; +} + +// RGB Matrix shaper +static +cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) +{ + cmsPipeline* Lut; + cmsMAT3 Mat; + cmsToneCurve *Shapes[3]; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + int i, j; + + if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) return NULL; + + // XYZ PCS in encoded in 1.15 format, and the matrix output comes in 0..0xffff range, so + // we need to adjust the output by a factor of (0x10000/0xffff) to put data in + // a 1.16 range, and then a >> 1 to obtain 1.15. The total factor is (65536.0)/(65535.0*2) + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + Mat.v[i].n[j] *= InpAdj; + + + Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); + Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); + Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); + + if (!Shapes[0] || !Shapes[1] || !Shapes[2]) + return NULL; + + Lut = cmsPipelineAlloc(ContextID, 3, 3); + if (Lut != NULL) { + + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)); + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL)); + } + + return Lut; +} + +// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc +// is adjusted here in order to create a LUT that takes care of all those details +cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) +{ + cmsTagTypeSignature OriginalType; + cmsTagSignature tag16 = Device2PCS16[Intent]; + cmsTagSignature tagFloat = Device2PCSFloat[Intent]; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4, so no adjustment is required + return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + } + + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = Device2PCS16[0]; + } + + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // After reading it, we have now info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + + // We need to adjust data only for Lab16 on output + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // Add a matrix for conversion V2 to V4 Lab PCS + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + return Lut; + } + + // Lut was not found, try to create a matrix-shaper + + // Check if this is a grayscale profile. + if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { + + // if so, build appropiate conversion tables. + // The tables are the PCS iluminant, scaled across GrayTRC + return BuildGrayInputMatrixPipeline(hProfile); + } + + // Not gray, create a normal matrix-shaper + return BuildRGBInputMatrixShaper(hProfile); +} + +// --------------------------------------------------------------------------------------------------------------- + +// Gray output pipeline. +// XYZ -> Gray or Lab -> Gray. Since we only know the GrayTRC, we need to do some assumptions. Gray component will be +// given by Y on XYZ PCS and by L* on Lab PCS, Both across inverse TRC curve. +// The complete pipeline on XYZ is Matrix[3:1] -> Tone curve and in Lab Matrix[3:1] -> Tone Curve as well. + +static +cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile) +{ + cmsToneCurve *GrayTRC, *RevGrayTRC; + cmsPipeline* Lut; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); + if (GrayTRC == NULL) return NULL; + + RevGrayTRC = cmsReverseToneCurve(GrayTRC); + if (RevGrayTRC == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 3, 1); + if (Lut == NULL) { + cmsFreeToneCurve(RevGrayTRC); + return NULL; + } + + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)); + } + else { + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL)); + } + + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC)); + cmsFreeToneCurve(RevGrayTRC); + + return Lut; +} + + + + +static +cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) +{ + cmsPipeline* Lut; + cmsToneCurve *Shapes[3], *InvShapes[3]; + cmsMAT3 Mat, Inv; + int i, j; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) + return NULL; + + if (!_cmsMAT3inverse(&Mat, &Inv)) + return NULL; + + // XYZ PCS in encoded in 1.15 format, and the matrix input should come in 0..0xffff range, so + // we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of + // (0xffff/0x10000) to put data in 0..0xffff range. Total factor is (2.0*65535.0)/65536.0; + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + Inv.v[i].n[j] *= OutpAdj; + + Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); + Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); + Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); + + if (!Shapes[0] || !Shapes[1] || !Shapes[2]) + return NULL; + + InvShapes[0] = cmsReverseToneCurve(Shapes[0]); + InvShapes[1] = cmsReverseToneCurve(Shapes[1]); + InvShapes[2] = cmsReverseToneCurve(Shapes[2]); + + if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) { + return NULL; + } + + Lut = cmsPipelineAlloc(ContextID, 3, 3); + if (Lut != NULL) { + + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)); + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes)); + } + + cmsFreeToneCurveTriple(InvShapes); + return Lut; +} + + +// Change CLUT interpolation to trilinear +static +void ChangeInterpolationToTrilinear(cmsPipeline* Lut) +{ + cmsStage* Stage; + + for (Stage = cmsPipelineGetPtrToFirstStage(Lut); + Stage != NULL; + Stage = cmsStageNext(Stage)) { + + if (cmsStageType(Stage) == cmsSigCLutElemType) { + + _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; + + CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; + _cmsSetInterpolationRoutine(CLUT ->Params); + } + } +} + +// Create an output MPE LUT from agiven profile. Version mismatches are handled here +cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) +{ + cmsTagTypeSignature OriginalType; + cmsTagSignature tag16 = PCS2Device16[Intent]; + cmsTagSignature tagFloat = PCS2DeviceFloat[Intent]; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4, so no adjustment is required + return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + } + + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = PCS2Device16[0]; + } + + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; + + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); + + // We need to adjust data only for Lab and Lut16 type + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // Add a matrix for conversion V4 to V2 Lab PCS + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + return Lut; + } + + // Lut not found, try to create a matrix-shaper + + // Check if this is a grayscale profile. + if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { + + // if so, build appropiate conversion tables. + // The tables are the PCS iluminant, scaled across GrayTRC + return BuildGrayOutputPipeline(hProfile); + } + + // Not gray, create a normal matrix-shaper + return BuildRGBOutputMatrixShaper(hProfile); +} + +// --------------------------------------------------------------------------------------------------------------- + +// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The +// tag name here may default to AToB0 +cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) +{ + cmsPipeline* Lut; + cmsTagTypeSignature OriginalType; + cmsTagSignature tag16 = Device2PCS16[Intent]; + cmsTagSignature tagFloat = Device2PCSFloat[Intent]; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4, no adjustment is required + return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + } + + tagFloat = Device2PCSFloat[0]; + if (cmsIsTag(hProfile, tagFloat)) { + + return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + } + + if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + tag16 = Device2PCS16[0]; + if (!cmsIsTag(hProfile, tag16)) return NULL; + } + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // Read the tag + Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; + + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); + + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // We need to adjust data for Lab16 on output + if (OriginalType != cmsSigLut16Type) return Lut; + + // Here it is possible to get Lab on both sides + + if (cmsGetPCS(hProfile) == cmsSigLabData) { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + } + + if (cmsGetColorSpace(hProfile) == cmsSigLabData) { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + } + + return Lut; + + +} + +// --------------------------------------------------------------------------------------------------------------- + +// Returns TRUE if the profile is implemented as matrix-shaper +cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile) +{ + switch (cmsGetColorSpace(hProfile)) { + + case cmsSigGrayData: + + return cmsIsTag(hProfile, cmsSigGrayTRCTag); + + case cmsSigRgbData: + + return (cmsIsTag(hProfile, cmsSigRedColorantTag) && + cmsIsTag(hProfile, cmsSigGreenColorantTag) && + cmsIsTag(hProfile, cmsSigBlueColorantTag) && + cmsIsTag(hProfile, cmsSigRedTRCTag) && + cmsIsTag(hProfile, cmsSigGreenTRCTag) && + cmsIsTag(hProfile, cmsSigBlueTRCTag)); + + default: + + return FALSE; + } +} + +// Returns TRUE if the intent is implemented as CLUT +cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection) +{ + const cmsTagSignature* TagTable; + + // For devicelinks, the supported intent is that one stated in the header + if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { + return (cmsGetHeaderRenderingIntent(hProfile) == Intent); + } + + switch (UsedDirection) { + + case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break; + case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break; + + // For proofing, we need rel. colorimetric in output. Let's do some recursion + case LCMS_USED_AS_PROOF: + return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) && + cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT); + + default: + cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_RANGE, "Unexpected direction (%d)", UsedDirection); + return FALSE; + } + + return cmsIsTag(hProfile, TagTable[Intent]); + +} + + +// Return info about supported intents +cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number UsedDirection) +{ + + if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE; + + // Is there any matrix-shaper? If so, the intent is supported. This is a bit odd, since V2 matrix shaper + // does not fully support relative colorimetric because they cannot deal with non-zero black points, but + // many profiles claims that, and this is certainly not true for V4 profiles. Lets answer "yes" no matter + // the accuracy would be less than optimal in rel.col and v2 case. + + return cmsIsMatrixShaper(hProfile); +} + + +// --------------------------------------------------------------------------------------------------------------- + +// Read both, profile sequence description and profile sequence id if present. Then combine both to +// create qa unique structure holding both. Shame on ICC to store things in such complicated way. + +cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) +{ + cmsSEQ* ProfileSeq; + cmsSEQ* ProfileId; + cmsSEQ* NewSeq; + cmsUInt32Number i; + + // Take profile sequence description first + ProfileSeq = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceDescTag); + + // Take profile sequence ID + ProfileId = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceIdTag); + + if (ProfileSeq == NULL && ProfileId == NULL) return NULL; + + if (ProfileSeq == NULL) return cmsDupProfileSequenceDescription(ProfileId); + if (ProfileId == NULL) return cmsDupProfileSequenceDescription(ProfileSeq); + + // We have to mix both together. For that they must agree + if (ProfileSeq ->n != ProfileId ->n) return cmsDupProfileSequenceDescription(ProfileSeq); + + NewSeq = cmsDupProfileSequenceDescription(ProfileSeq); + + // Ok, proceed to the mixing + for (i=0; i < ProfileSeq ->n; i++) { + + memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID)); + NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description); + } + + return NewSeq; +} + +// Dump the contents of profile sequence in both tags (if v4 available) +cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq) +{ + if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE; + + if (cmsGetProfileVersion(hProfile) >= 4.0) { + + if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE; + } + + return TRUE; +} + + +// Auxiliar, read and duplicate a MLU if found. +static +cmsMLU* GetMLUFromProfile(cmsHPROFILE h, cmsTagSignature sig) +{ + cmsMLU* mlu = (cmsMLU*) cmsReadTag(h, sig); + if (mlu == NULL) return NULL; + + return cmsMLUdup(mlu); +} + +// Create a sequence description out of an array of profiles +cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]) +{ + cmsUInt32Number i; + cmsSEQ* seq = cmsAllocProfileSequenceDescription(ContextID, nProfiles); + + if (seq == NULL) return NULL; + + for (i=0; i < nProfiles; i++) { + + cmsPSEQDESC* ps = &seq ->seq[i]; + cmsHPROFILE h = hProfiles[i]; + cmsTechnologySignature* techpt; + + cmsGetHeaderAttributes(h, &ps ->attributes); + cmsGetHeaderProfileID(h, ps ->ProfileID.ID8); + ps ->deviceMfg = cmsGetHeaderManufacturer(h); + ps ->deviceModel = cmsGetHeaderModel(h); + + techpt = (cmsTechnologySignature*) cmsReadTag(h, cmsSigTechnologyTag); + if (techpt == NULL) + ps ->technology = (cmsTechnologySignature) 0; + else + ps ->technology = *techpt; + + ps ->Manufacturer = GetMLUFromProfile(h, cmsSigDeviceMfgDescTag); + ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag); + ps ->Description = GetMLUFromProfile(h, cmsSigProfileDescriptionTag); + + } + + return seq; +} + +// ------------------------------------------------------------------------------------------------------------------- + + +static +const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info) +{ + cmsTagSignature sig; + + switch (Info) { + + case cmsInfoDescription: + sig = cmsSigProfileDescriptionTag; + break; + + case cmsInfoManufacturer: + sig = cmsSigDeviceMfgDescTag; + break; + + case cmsInfoModel: + sig = cmsSigDeviceModelDescTag; + break; + + case cmsInfoCopyright: + sig = cmsSigCopyrightTag; + break; + + default: return NULL; + } + + + return (cmsMLU*) cmsReadTag(hProfile, sig); +} + + + +cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize) +{ + const cmsMLU* mlu = GetInfo(hProfile, Info); + if (mlu == NULL) return 0; + + return cmsMLUgetWide(mlu, LanguageCode, CountryCode, Buffer, BufferSize); +} + + +cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const cmsMLU* mlu = GetInfo(hProfile, Info); + if (mlu == NULL) return 0; + + return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize); +} diff --git a/thirdparty/liblcms2/src/cmslut.c b/thirdparty/liblcms2/src/cmslut.c new file mode 100644 index 00000000..d0fe9c80 --- /dev/null +++ b/thirdparty/liblcms2/src/cmslut.c @@ -0,0 +1,1665 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// Allocates an empty multi profile element +cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, + cmsStageSignature Type, + cmsUInt32Number InputChannels, + cmsUInt32Number OutputChannels, + _cmsStageEvalFn EvalPtr, + _cmsStageDupElemFn DupElemPtr, + _cmsStageFreeElemFn FreePtr, + void* Data) +{ + cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); + + if (ph == NULL) return NULL; + + + ph ->ContextID = ContextID; + + ph ->Type = Type; + ph ->Implements = Type; // By default, no clue on what is implementing + + ph ->InputChannels = InputChannels; + ph ->OutputChannels = OutputChannels; + ph ->EvalPtr = EvalPtr; + ph ->DupElemPtr = DupElemPtr; + ph ->FreePtr = FreePtr; + ph ->Data = Data; + + return ph; +} + + +static +void EvaluateIdentity(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); +} + + +cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) +{ + return _cmsStageAllocPlaceholder(ContextID, + cmsSigIdentityElemType, + nChannels, nChannels, + EvaluateIdentity, + NULL, + NULL, + NULL); + } + +// Conversion functions. From floating point to 16 bits +static +void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32Number n) +{ + cmsUInt32Number i; + + for (i=0; i < n; i++) { + Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); + } +} + +// From 16 bits to floating point +static +void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32Number n) +{ + cmsUInt32Number i; + + for (i=0; i < n; i++) { + Out[i] = (cmsFloat32Number) In[i] / 65535.0F; + } +} + + +// This function is quite useful to analyze the structure of a LUT and retrieve the MPE elements +// that conform the LUT. It should be called with the LUT, the number of expected elements and +// then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If +// the function founds a match with current pipeline, it fills the pointers and returns TRUE +// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass +// the storage process. +cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) +{ + va_list args; + cmsUInt32Number i; + cmsStage* mpe; + cmsStageSignature Type; + void** ElemPtr; + + // Make sure same number of elements + if (cmsPipelineStageCount(Lut) != n) return FALSE; + + va_start(args, n); + + // Iterate across asked types + mpe = Lut ->Elements; + for (i=0; i < n; i++) { + + // Get asked type + Type = va_arg(args, cmsStageSignature); + if (mpe ->Type != Type) { + + va_end(args); // Mismatch. We are done. + return FALSE; + } + mpe = mpe ->Next; + } + + // Found a combination, fill pointers if not NULL + mpe = Lut ->Elements; + for (i=0; i < n; i++) { + + ElemPtr = va_arg(args, void**); + if (ElemPtr != NULL) + *ElemPtr = mpe; + + mpe = mpe ->Next; + } + + va_end(args); + return TRUE; +} + +// Below there are implementations for several types of elements. Each type may be implemented by a +// evaluation function, a duplication function, a function to free resources and a constructor. + +// ************************************************************************************************* +// Type cmsSigCurveSetElemType (curves) +// ************************************************************************************************* + +cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) +{ + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; + + return Data ->TheCurves; +} + +static +void EvaluateCurves(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + _cmsStageToneCurvesData* Data; + cmsUInt32Number i; + + _cmsAssert(mpe != NULL); + + Data = (_cmsStageToneCurvesData*) mpe ->Data; + if (Data == NULL) return; + + if (Data ->TheCurves == NULL) return; + + for (i=0; i < Data ->nCurves; i++) { + Out[i] = cmsEvalToneCurveFloat(Data ->TheCurves[i], In[i]); + } +} + +static +void CurveSetElemTypeFree(cmsStage* mpe) +{ + _cmsStageToneCurvesData* Data; + cmsUInt32Number i; + + _cmsAssert(mpe != NULL); + + Data = (_cmsStageToneCurvesData*) mpe ->Data; + if (Data == NULL) return; + + if (Data ->TheCurves != NULL) { + for (i=0; i < Data ->nCurves; i++) { + if (Data ->TheCurves[i] != NULL) + cmsFreeToneCurve(Data ->TheCurves[i]); + } + } + _cmsFree(mpe ->ContextID, Data ->TheCurves); + _cmsFree(mpe ->ContextID, Data); +} + + +static +void* CurveSetDup(cmsStage* mpe) +{ + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; + _cmsStageToneCurvesData* NewElem; + cmsUInt32Number i; + + NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageToneCurvesData)); + if (NewElem == NULL) return NULL; + + NewElem ->nCurves = Data ->nCurves; + NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(mpe ->ContextID, NewElem ->nCurves, sizeof(cmsToneCurve*)); + + if (NewElem ->TheCurves == NULL) goto Error; + + for (i=0; i < NewElem ->nCurves; i++) { + + // Duplicate each curve. It may fail. + NewElem ->TheCurves[i] = cmsDupToneCurve(Data ->TheCurves[i]); + if (NewElem ->TheCurves[i] == NULL) goto Error; + + + } + return (void*) NewElem; + +Error: + + if (NewElem ->TheCurves != NULL) { + for (i=0; i < NewElem ->nCurves; i++) { + if (NewElem ->TheCurves[i]) + cmsFreeToneCurve(Data ->TheCurves[i]); + } + } + _cmsFree(mpe ->ContextID, Data ->TheCurves); + _cmsFree(mpe ->ContextID, NewElem); + return NULL; +} + + +// Curves == NULL forces identity curves +cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]) +{ + cmsUInt32Number i; + _cmsStageToneCurvesData* NewElem; + cmsStage* NewMPE; + + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, + EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); + if (NewMPE == NULL) return NULL; + + NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + NewMPE ->Data = (void*) NewElem; + + NewElem ->nCurves = nChannels; + NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); + if (NewElem ->TheCurves == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + for (i=0; i < nChannels; i++) { + + if (Curves == NULL) { + NewElem ->TheCurves[i] = cmsBuildGamma(ContextID, 1.0); + } + else { + NewElem ->TheCurves[i] = cmsDupToneCurve(Curves[i]); + } + + if (NewElem ->TheCurves[i] == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + } + + return NewMPE; +} + + +// Create a bunch of identity curves +cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) +{ + cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); + + if (mpe == NULL) return NULL; + mpe ->Implements = cmsSigIdentityElemType; + return mpe; +} + + +// ************************************************************************************************* +// Type cmsSigMatrixElemType (Matrices) +// ************************************************************************************************* + + +// Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used +static +void EvaluateMatrix(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + cmsUInt32Number i, j; + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + cmsFloat64Number Tmp; + + // Input is already in 0..1.0 notation + for (i=0; i < mpe ->OutputChannels; i++) { + + Tmp = 0; + for (j=0; j < mpe->InputChannels; j++) { + Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; + } + + if (Data ->Offset != NULL) + Tmp += Data->Offset[i]; + + Out[i] = (cmsFloat32Number) Tmp; + } + + + // Output in 0..1.0 domain +} + + +// Duplicate a yet-existing matrix element +static +void* MatrixElemDup(cmsStage* mpe) +{ + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + _cmsStageMatrixData* NewElem; + cmsUInt32Number sz; + + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); + if (NewElem == NULL) return NULL; + + sz = mpe ->InputChannels * mpe ->OutputChannels; + + NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; + + if (Data ->Offset) + NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, + Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; + + return (void*) NewElem; +} + + +static +void MatrixElemTypeFree(cmsStage* mpe) +{ + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + if (Data ->Double) + _cmsFree(mpe ->ContextID, Data ->Double); + + if (Data ->Offset) + _cmsFree(mpe ->ContextID, Data ->Offset); + + _cmsFree(mpe ->ContextID, mpe ->Data); +} + + + +cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, + const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) +{ + cmsUInt32Number i, n; + _cmsStageMatrixData* NewElem; + cmsStage* NewMPE; + + n = Rows * Cols; + + // Check for overflow + if (n == 0) return NULL; + if (n >= UINT_MAX / Cols) return NULL; + if (n >= UINT_MAX / Rows) return NULL; + if (n < Rows || n < Cols) return NULL; + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows, + EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); + if (NewMPE == NULL) return NULL; + + + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); + if (NewElem == NULL) return NULL; + + + NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); + + if (NewElem->Double == NULL) { + MatrixElemTypeFree(NewMPE); + return NULL; + } + + for (i=0; i < n; i++) { + NewElem ->Double[i] = Matrix[i]; + } + + + if (Offset != NULL) { + + NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); + if (NewElem->Offset == NULL) { + MatrixElemTypeFree(NewMPE); + return NULL; + } + + for (i=0; i < Cols; i++) { + NewElem ->Offset[i] = Offset[i]; + } + + } + + NewMPE ->Data = (void*) NewElem; + return NewMPE; +} + + +// ************************************************************************************************* +// Type cmsSigCLutElemType +// ************************************************************************************************* + + +// Evaluate in true floating point +static +void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + + Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); +} + + +// Convert to 16 bits, evaluate, and back to floating point +static +void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; + + _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); + _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); + + FromFloatTo16(In, In16, mpe ->InputChannels); + Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); + From16ToFloat(Out16, Out, mpe ->OutputChannels); +} + + +// Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes +static +cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) +{ + cmsUInt32Number rv, dim; + + _cmsAssert(Dims != NULL); + + for (rv = 1; b > 0; b--) { + + dim = Dims[b-1]; + if (dim == 0) return 0; // Error + + rv *= dim; + + // Check for overflow + if (rv > UINT_MAX / dim) return 0; + } + + return rv; +} + +static +void* CLUTElemDup(cmsStage* mpe) +{ + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + _cmsStageCLutData* NewElem; + + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) return NULL; + + NewElem ->nEntries = Data ->nEntries; + NewElem ->HasFloatValues = Data ->HasFloatValues; + + if (Data ->Tab.T) { + + if (Data ->HasFloatValues) + NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); + else + NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); + } + + NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, + Data ->Params ->nSamples, + Data ->Params ->nInputs, + Data ->Params ->nOutputs, + NewElem ->Tab.T, + Data ->Params ->dwFlags); + + return (void*) NewElem; +} + + +static +void CLutElemTypeFree(cmsStage* mpe) +{ + + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + + // Already empty + if (Data == NULL) return; + + // This works for both types + if (Data -> Tab.T) + _cmsFree(mpe ->ContextID, Data -> Tab.T); + + _cmsFreeInterpParams(Data ->Params); + _cmsFree(mpe ->ContextID, mpe ->Data); +} + + +// Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different +// granularity on each dimension. +cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, + const cmsUInt32Number clutPoints[], + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, + const cmsUInt16Number* Table) +{ + cmsUInt32Number i, n; + _cmsStageCLutData* NewElem; + cmsStage* NewMPE; + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, + EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); + + if (NewMPE == NULL) return NULL; + + NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + NewMPE ->Data = (void*) NewElem; + + NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); + NewElem -> HasFloatValues = FALSE; + + if (n == 0) { + cmsStageFree(NewMPE); + return NULL; + } + + + NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number)); + if (NewElem ->Tab.T == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + if (Table != NULL) { + for (i=0; i < n; i++) { + NewElem ->Tab.T[i] = Table[i]; + } + } + + NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS); + if (NewElem ->Params == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + return NewMPE; +} + +cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, + const cmsUInt16Number* Table) +{ + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; + + // Our resulting LUT would be same gridpoints on all dimensions + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Dimensions[i] = nGridPoints; + + + return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); +} + + +cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, + const cmsFloat32Number* Table) +{ + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; + + // Our resulting LUT would be same gridpoints on all dimensions + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Dimensions[i] = nGridPoints; + + return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table); +} + + + +cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table) +{ + cmsUInt32Number i, n; + _cmsStageCLutData* NewElem; + cmsStage* NewMPE; + + _cmsAssert(clutPoints != NULL); + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, + EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); + if (NewMPE == NULL) return NULL; + + + NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + NewMPE ->Data = (void*) NewElem; + + // There is a potential integer overflow on conputing n and nEntries. + NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan); + NewElem -> HasFloatValues = TRUE; + + if (n == 0) { + cmsStageFree(NewMPE); + return NULL; + } + + NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number)); + if (NewElem ->Tab.TFloat == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + if (Table != NULL) { + for (i=0; i < n; i++) { + NewElem ->Tab.TFloat[i] = Table[i]; + } + } + + + + NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); + if (NewElem ->Params == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + + + return NewMPE; +} + + +static +int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) +{ + int nChan = *(int*) Cargo; + int i; + + for (i=0; i < nChan; i++) + Out[i] = In[i]; + + return 1; +} + +// Creates an MPE that just copies input to output +cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan) +{ + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + cmsStage* mpe ; + int i; + + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Dimensions[i] = 2; + + mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); + if (mpe == NULL) return NULL; + + if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { + cmsStageFree(mpe); + return NULL; + } + + mpe ->Implements = cmsSigIdentityElemType; + return mpe; +} + + + +// Quantize a value 0 <= i < MaxSamples to 0..0xffff +cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples) +{ + cmsFloat64Number x; + + x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1); + return _cmsQuickSaturateWord(x); +} + + +// This routine does a sweep on whole input space, and calls its callback +// function on knots. returns TRUE if all ok, FALSE otherwise. +cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) +{ + int i, t, nTotalPoints, index, rest; + int nInputs, nOutputs; + cmsUInt32Number* nSamples; + cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + + + nSamples = clut->Params ->nSamples; + nInputs = clut->Params ->nInputs; + nOutputs = clut->Params ->nOutputs; + + if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; + + nTotalPoints = CubeSize(nSamples, nInputs); + if (nTotalPoints == 0) return FALSE; + + index = 0; + for (i = 0; i < nTotalPoints; i++) { + + rest = i; + for (t = nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % nSamples[t]; + + rest /= nSamples[t]; + + In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); + } + + if (clut ->Tab.T != NULL) { + for (t=0; t < nOutputs; t++) + Out[t] = clut->Tab.T[index + t]; + } + + if (!Sampler(In, Out, Cargo)) + return FALSE; + + if (!(dwFlags & SAMPLER_INSPECT)) { + + if (clut ->Tab.T != NULL) { + for (t=0; t < nOutputs; t++) + clut->Tab.T[index + t] = Out[t]; + } + } + + index += nOutputs; + } + + return TRUE; +} + +// Same as anterior, but for floting point +cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags) +{ + int i, t, nTotalPoints, index, rest; + int nInputs, nOutputs; + cmsUInt32Number* nSamples; + cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + + nSamples = clut->Params ->nSamples; + nInputs = clut->Params ->nInputs; + nOutputs = clut->Params ->nOutputs; + + if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; + + nTotalPoints = CubeSize(nSamples, nInputs); + if (nTotalPoints == 0) return FALSE; + + index = 0; + for (i = 0; i < nTotalPoints; i++) { + + rest = i; + for (t = nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % nSamples[t]; + + rest /= nSamples[t]; + + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); + } + + if (clut ->Tab.TFloat != NULL) { + for (t=0; t < nOutputs; t++) + Out[t] = clut->Tab.TFloat[index + t]; + } + + if (!Sampler(In, Out, Cargo)) + return FALSE; + + if (!(dwFlags & SAMPLER_INSPECT)) { + + if (clut ->Tab.TFloat != NULL) { + for (t=0; t < nOutputs; t++) + clut->Tab.TFloat[index + t] = Out[t]; + } + } + + index += nOutputs; + } + + return TRUE; +} + + + +// This routine does a sweep on whole input space, and calls its callback +// function on knots. returns TRUE if all ok, FALSE otherwise. +cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLER16 Sampler, void * Cargo) +{ + int i, t, nTotalPoints, rest; + cmsUInt16Number In[cmsMAXCHANNELS]; + + if (nInputs >= cmsMAXCHANNELS) return FALSE; + + nTotalPoints = CubeSize(clutPoints, nInputs); + if (nTotalPoints == 0) return FALSE; + + for (i = 0; i < nTotalPoints; i++) { + + rest = i; + for (t = nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % clutPoints[t]; + + rest /= clutPoints[t]; + In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); + + } + + if (!Sampler(In, NULL, Cargo)) + return FALSE; + } + + return TRUE; +} + +cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLERFLOAT Sampler, void * Cargo) +{ + int i, t, nTotalPoints, rest; + cmsFloat32Number In[cmsMAXCHANNELS]; + + if (nInputs >= cmsMAXCHANNELS) return FALSE; + + nTotalPoints = CubeSize(clutPoints, nInputs); + if (nTotalPoints == 0) return FALSE; + + for (i = 0; i < nTotalPoints; i++) { + + rest = i; + for (t = nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % clutPoints[t]; + + rest /= clutPoints[t]; + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); + + } + + if (!Sampler(In, NULL, Cargo)) + return FALSE; + } + + return TRUE; +} + +// ******************************************************************************** +// Type cmsSigLab2XYZElemType +// ******************************************************************************** + + +static +void EvaluateLab2XYZ(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + cmsCIELab Lab; + cmsCIEXYZ XYZ; + const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; + + // V4 rules + Lab.L = In[0] * 100.0; + Lab.a = In[1] * 255.0 - 128.0; + Lab.b = In[2] * 255.0 - 128.0; + + cmsLab2XYZ(NULL, &XYZ, &Lab); + + // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff + // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) + + Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); + Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); + Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); + return; + + cmsUNUSED_PARAMETER(mpe); +} + + +// No dup or free routines needed, as the structure has no pointers in it. +cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID) +{ + return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL); +} + +// ******************************************************************************** + +// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable +// number of gridpoints that would make exact match. However, a prelinearization +// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. +// Almost all what we need but unfortunately, the rest of entries should be scaled by +// (255*257/256) and this is not exact. + +cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) +{ + cmsStage* mpe; + cmsToneCurve* LabTable[3]; + int i, j; + + LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); + LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); + LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); + + for (j=0; j < 3; j++) { + + if (LabTable[j] == NULL) { + cmsFreeToneCurveTriple(LabTable); + return NULL; + } + + // We need to map * (0xffff / 0xff00), thats same as (257 / 256) + // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); + for (i=0; i < 257; i++) { + + LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8); + } + + LabTable[j] ->Table16[257] = 0xffff; + } + + mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); + cmsFreeToneCurveTriple(LabTable); + + mpe ->Implements = cmsSigLabV2toV4; + return mpe; +} + +// ******************************************************************************** + +// Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles +cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) +{ + static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, + 0, 65535.0/65280.0, 0, + 0, 0, 65535.0/65280.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLabV2toV4; + return mpe; +} + + +// Reverse direction +cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) +{ + static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, + 0, 65280.0/65535.0, 0, + 0, 0, 65280.0/65535.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLabV4toV2; + return mpe; +} + + +// ******************************************************************************** +// Type cmsSigXYZ2LabElemType +// ******************************************************************************** + +static +void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsCIELab Lab; + cmsCIEXYZ XYZ; + const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; + + // From 0..1.0 to XYZ + + XYZ.X = In[0] * XYZadj; + XYZ.Y = In[1] * XYZadj; + XYZ.Z = In[2] * XYZadj; + + cmsXYZ2Lab(NULL, &Lab, &XYZ); + + // From V4 Lab to 0..1.0 + + Out[0] = (cmsFloat32Number) (Lab.L / 100.0); + Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); + Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); + return; + + cmsUNUSED_PARAMETER(mpe); +} + +cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID) +{ + return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); + +} + +// ******************************************************************************** + +// For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray + +cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) +{ + cmsToneCurve* LabTable[3]; + cmsFloat64Number Params[1] = {2.4} ; + + LabTable[0] = cmsBuildGamma(ContextID, 1.0); + LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params); + LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params); + + return cmsStageAllocToneCurves(ContextID, 3, LabTable); +} + + +// Free a single MPE +void CMSEXPORT cmsStageFree(cmsStage* mpe) +{ + if (mpe ->FreePtr) + mpe ->FreePtr(mpe); + + _cmsFree(mpe ->ContextID, mpe); +} + + +cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe) +{ + return mpe ->InputChannels; +} + +cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe) +{ + return mpe ->OutputChannels; +} + +cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe) +{ + return mpe -> Type; +} + +void* CMSEXPORT cmsStageData(const cmsStage* mpe) +{ + return mpe -> Data; +} + +cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) +{ + return mpe -> Next; +} + + +// Duplicates an MPE +cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) +{ + cmsStage* NewMPE; + + if (mpe == NULL) return NULL; + NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, + mpe ->Type, + mpe ->InputChannels, + mpe ->OutputChannels, + mpe ->EvalPtr, + mpe ->DupElemPtr, + mpe ->FreePtr, + NULL); + if (NewMPE == NULL) return NULL; + + NewMPE ->Implements = mpe ->Implements; + + if (mpe ->DupElemPtr) + NewMPE ->Data = mpe ->DupElemPtr(mpe); + else + NewMPE ->Data = NULL; + + return NewMPE; +} + + +// *********************************************************************************************************** + +// This function sets up the channel count + +static +void BlessLUT(cmsPipeline* lut) +{ + // We can set the input/ouput channels only if we have elements. + if (lut ->Elements != NULL) { + + cmsStage *First, *Last; + + First = cmsPipelineGetPtrToFirstStage(lut); + Last = cmsPipelineGetPtrToLastStage(lut); + + if (First != NULL)lut ->InputChannels = First ->InputChannels; + if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels; + } +} + + +// Default to evaluate the LUT on 16 bit-basis. Precision is retained. +static +void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) +{ + cmsPipeline* lut = (cmsPipeline*) D; + cmsStage *mpe; + cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; + int Phase = 0, NextPhase; + + From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + NextPhase = Phase ^ 1; + mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); + Phase = NextPhase; + } + + + FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); +} + + + +// Does evaluate the LUT on cmsFloat32Number-basis. +static +void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) +{ + cmsPipeline* lut = (cmsPipeline*) D; + cmsStage *mpe; + cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; + int Phase = 0, NextPhase; + + memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + NextPhase = Phase ^ 1; + mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); + Phase = NextPhase; + } + + memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); +} + + + + +// LUT Creation & Destruction + +cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) +{ + cmsPipeline* NewLUT; + + if (InputChannels >= cmsMAXCHANNELS || + OutputChannels >= cmsMAXCHANNELS) return NULL; + + NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline)); + if (NewLUT == NULL) return NULL; + + + NewLUT -> InputChannels = InputChannels; + NewLUT -> OutputChannels = OutputChannels; + + NewLUT ->Eval16Fn = _LUTeval16; + NewLUT ->EvalFloatFn = _LUTevalFloat; + NewLUT ->DupDataFn = NULL; + NewLUT ->FreeDataFn = NULL; + NewLUT ->Data = NewLUT; + NewLUT ->ContextID = ContextID; + + BlessLUT(NewLUT); + + return NewLUT; +} + + +cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) +{ + return lut ->InputChannels; +} + +cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) +{ + return lut ->OutputChannels; +} + +// Free a profile elements LUT +void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) +{ + cmsStage *mpe, *Next; + + if (lut == NULL) return; + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = Next) { + + Next = mpe ->Next; + cmsStageFree(mpe); + } + + if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); + + _cmsFree(lut ->ContextID, lut); +} + + +// Default to evaluate the LUT on 16 bit-basis. +void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) +{ + lut ->Eval16Fn(In, Out, lut->Data); +} + + +// Does evaluate the LUT on cmsFloat32Number-basis. +void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) +{ + lut ->EvalFloatFn(In, Out, lut); +} + + + +// Duplicates a LUT +cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) +{ + cmsPipeline* NewLUT; + cmsStage *NewMPE, *Anterior = NULL, *mpe; + cmsBool First = TRUE; + + if (lut == NULL) return NULL; + + NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); + for (mpe = lut ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + NewMPE = cmsStageDup(mpe); + + if (NewMPE == NULL) { + cmsPipelineFree(NewLUT); + return NULL; + } + + if (First) { + NewLUT ->Elements = NewMPE; + First = FALSE; + } + else { + Anterior ->Next = NewMPE; + } + + Anterior = NewMPE; + } + + NewLUT ->DupDataFn = lut ->DupDataFn; + NewLUT ->FreeDataFn = lut ->FreeDataFn; + + if (NewLUT ->DupDataFn != NULL) + NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); + + + NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; + + BlessLUT(NewLUT); + return NewLUT; +} + + +void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) +{ + cmsStage* Anterior = NULL, *pt; + + _cmsAssert(lut != NULL); + _cmsAssert(mpe != NULL); + + switch (loc) { + + case cmsAT_BEGIN: + mpe ->Next = lut ->Elements; + lut ->Elements = mpe; + break; + + case cmsAT_END: + + if (lut ->Elements == NULL) + lut ->Elements = mpe; + else { + + for (pt = lut ->Elements; + pt != NULL; + pt = pt -> Next) Anterior = pt; + + Anterior ->Next = mpe; + mpe ->Next = NULL; + } + break; + default:; + } + + BlessLUT(lut); +} + +// Unlink an element and return the pointer to it +void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe) +{ + cmsStage *Anterior, *pt, *Last; + cmsStage *Unlinked = NULL; + + + // If empty LUT, there is nothing to remove + if (lut ->Elements == NULL) { + if (mpe) *mpe = NULL; + return; + } + + // On depending on the strategy... + switch (loc) { + + case cmsAT_BEGIN: + { + cmsStage* elem = lut ->Elements; + + lut ->Elements = elem -> Next; + elem ->Next = NULL; + Unlinked = elem; + + } + break; + + case cmsAT_END: + Anterior = Last = NULL; + for (pt = lut ->Elements; + pt != NULL; + pt = pt -> Next) { + Anterior = Last; + Last = pt; + } + + Unlinked = Last; // Next already points to NULL + + // Truncate the chain + if (Anterior) + Anterior ->Next = NULL; + else + lut ->Elements = NULL; + break; + default:; + } + + if (mpe) + *mpe = Unlinked; + else + cmsStageFree(Unlinked); + + BlessLUT(lut); +} + + +// Concatenate two LUT into a new single one +cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) +{ + cmsStage* mpe, *NewMPE; + + // If both LUTS does not have elements, we need to inherit + // the number of channels + if (l1 ->Elements == NULL && l2 ->Elements == NULL) { + l1 ->InputChannels = l2 ->InputChannels; + l1 ->OutputChannels = l2 ->OutputChannels; + } + + // Cat second + for (mpe = l2 ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + // We have to dup each element + NewMPE = cmsStageDup(mpe); + + if (NewMPE == NULL) { + return FALSE; + } + + cmsPipelineInsertStage(l1, cmsAT_END, NewMPE); + } + + BlessLUT(l1); + return TRUE; +} + + +cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On) +{ + cmsBool Anterior = lut ->SaveAs8Bits; + + lut ->SaveAs8Bits = On; + return Anterior; +} + + +cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut) +{ + return lut ->Elements; +} + +cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut) +{ + cmsStage *mpe, *Anterior = NULL; + + for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) + Anterior = mpe; + + return Anterior; +} + +cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) +{ + cmsStage *mpe; + cmsUInt32Number n; + + for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) + n++; + + return n; +} + +// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional +// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. +void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, + _cmsOPTeval16Fn Eval16, + void* PrivateData, + _cmsOPTfreeDataFn FreePrivateDataFn, + _cmsOPTdupDataFn DupPrivateDataFn) +{ + + Lut ->Eval16Fn = Eval16; + Lut ->DupDataFn = DupPrivateDataFn; + Lut ->FreeDataFn = FreePrivateDataFn; + Lut ->Data = PrivateData; +} + + +// ----------------------------------------------------------- Reverse interpolation +// Here's how it goes. The derivative Df(x) of the function f is the linear +// transformation that best approximates f near the point x. It can be represented +// by a matrix A whose entries are the partial derivatives of the components of f +// with respect to all the coordinates. This is know as the Jacobian +// +// The best linear approximation to f is given by the matrix equation: +// +// y-y0 = A (x-x0) +// +// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this +// linear approximation will give a "better guess" for the zero of f. Thus let y=0, +// and since y0=f(x0) one can solve the above equation for x. This leads to the +// Newton's method formula: +// +// xn+1 = xn - A-1 f(xn) +// +// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the +// fashion described above. Iterating this will give better and better approximations +// if you have a "good enough" initial guess. + + +#define JACOBIAN_EPSILON 0.001f +#define INVERSION_MAX_ITERATIONS 30 + +// Increment with reflexion on boundary +static +void IncDelta(cmsFloat32Number *Val) +{ + if (*Val < (1.0 - JACOBIAN_EPSILON)) + + *Val += JACOBIAN_EPSILON; + + else + *Val -= JACOBIAN_EPSILON; + +} + + + +// Euclidean distance between two vectors of n elements each one +static +cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n) +{ + cmsFloat32Number sum = 0; + int i; + + for (i=0; i < n; i++) { + cmsFloat32Number dif = b[i] - a[i]; + sum += dif * dif; + } + + return sqrtf(sum); +} + + +// Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method +// +// x1 <- x - [J(x)]^-1 * f(x) +// +// lut: The LUT on where to do the search +// Target: LabK, 3 values of Lab plus destination K which is fixed +// Result: The obtained CMYK +// Hint: Location where begin the search + +cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], + cmsFloat32Number Result[], + cmsFloat32Number Hint[], + const cmsPipeline* lut) +{ + cmsUInt32Number i, j; + cmsFloat64Number error, LastError = 1E20; + cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; + cmsVEC3 tmp, tmp2; + cmsMAT3 Jacobian; + cmsFloat64Number LastResult[4]; + + + // Only 3->3 and 4->3 are supported + if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; + if (lut ->OutputChannels != 3) return FALSE; + + // Mark result of -1 + LastResult[0] = LastResult[1] = LastResult[2] = -1.0f; + + // Take the hint as starting point if specified + if (Hint == NULL) { + + // Begin at any point, we choose 1/3 of CMY axis + x[0] = x[1] = x[2] = 0.3f; + } + else { + + // Only copy 3 channels from hint... + for (j=0; j < 3; j++) + x[j] = Hint[j]; + } + + // If Lut is 4-dimensions, then grab target[3], which is fixed + if (lut ->InputChannels == 4) { + x[3] = Target[3]; + } + else x[3] = 0; // To keep lint happy + + + // Iterate + for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { + + // Get beginning fx + cmsPipelineEvalFloat(x, fx, lut); + + // Compute error + error = EuclideanDistance(fx, Target, 3); + + // If not convergent, return last safe value + if (error >= LastError) + break; + + // Keep latest values + LastError = error; + for (j=0; j < lut ->InputChannels; j++) + Result[j] = x[j]; + + // Found an exact match? + if (error <= 0) + break; + + // Obtain slope (the Jacobian) + for (j = 0; j < 3; j++) { + + xd[0] = x[0]; + xd[1] = x[1]; + xd[2] = x[2]; + xd[3] = x[3]; // Keep fixed channel + + IncDelta(&xd[j]); + + cmsPipelineEvalFloat(xd, fxd, lut); + + Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); + Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); + Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); + } + + // Solve system + tmp2.n[0] = fx[0] - Target[0]; + tmp2.n[1] = fx[1] - Target[1]; + tmp2.n[2] = fx[2] - Target[2]; + + if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2)) + return FALSE; + + // Move our guess + x[0] -= (cmsFloat32Number) tmp.n[0]; + x[1] -= (cmsFloat32Number) tmp.n[1]; + x[2] -= (cmsFloat32Number) tmp.n[2]; + + // Some clipping.... + for (j=0; j < 3; j++) { + if (x[j] < 0) x[j] = 0; + else + if (x[j] > 1.0) x[j] = 1.0; + } + } + + return TRUE; +} + diff --git a/thirdparty/liblcms2/src/cmsmd5.c b/thirdparty/liblcms2/src/cmsmd5.c new file mode 100644 index 00000000..ecf3d907 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsmd5.c @@ -0,0 +1,317 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- + + +#include "lcms2_internal.h" + +#ifdef CMS_USE_BIG_ENDIAN + +static +void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs) +{ + do { + + cmsUInt32Number t = _cmsAdjustEndianess32(*(cmsUInt32Number *) buf); + *(cmsUInt32Number *) buf = t; + buf += sizeof(cmsUInt32Number); + + } while (--longs); + +} + +#else +#define byteReverse(buf, len) +#endif + + +typedef struct { + + cmsUInt32Number buf[4]; + cmsUInt32Number bits[2]; + cmsUInt8Number in[64]; + cmsContext ContextID; + +} _cmsMD5; + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + + +static +void MD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16]) + +{ + register cmsUInt32Number a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + + +// Create a MD5 object +static +cmsHANDLE MD5alloc(cmsContext ContextID) +{ + _cmsMD5* ctx = (_cmsMD5*) _cmsMallocZero(ContextID, sizeof(_cmsMD5)); + if (ctx == NULL) return NULL; + + ctx ->ContextID = ContextID; + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; + + return (cmsHANDLE) ctx; +} + + +static +void MD5add(cmsHANDLE Handle, cmsUInt8Number* buf, cmsUInt32Number len) +{ + _cmsMD5* ctx = (_cmsMD5*) Handle; + cmsUInt32Number t; + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + (len << 3)) < t) + ctx->bits[1]++; + + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; + + if (t) { + + cmsUInt8Number *p = (cmsUInt8Number *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memmove(p, buf, len); + return; + } + + memmove(p, buf, t); + byteReverse(ctx->in, 16); + + MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) { + memmove(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + buf += 64; + len -= 64; + } + + memmove(ctx->in, buf, len); +} + +// Destroy the object and return the checksum +static +void MD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle) +{ + _cmsMD5* ctx = (_cmsMD5*) Handle; + cmsUInt32Number count; + cmsUInt8Number *p; + + count = (ctx->bits[0] >> 3) & 0x3F; + + p = ctx->in + count; + *p++ = 0x80; + + count = 64 - 1 - count; + + if (count < 8) { + + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + ((cmsUInt32Number *) ctx->in)[14] = ctx->bits[0]; + ((cmsUInt32Number *) ctx->in)[15] = ctx->bits[1]; + + MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + + byteReverse((cmsUInt8Number *) ctx->buf, 4); + memmove(ProfileID ->ID8, ctx->buf, 16); + + _cmsFree(ctx ->ContextID, ctx); +} + + + +// Assuming io points to an ICC profile, compute and store MD5 checksum +// In the header, rendering intentent, attributes and ID should be set to zero +// before computing MD5 checksum (per 6.1.13 in ICC spec) + +cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) +{ + cmsContext ContextID; + cmsUInt32Number BytesNeeded; + cmsUInt8Number* Mem = NULL; + cmsHANDLE MD5 = NULL; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE Keep; + + _cmsAssert(hProfile != NULL); + + ContextID = cmsGetProfileContextID(hProfile); + + // Save a copy of the profile header + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); + + // Set RI, attributes and ID + memset(&Icc ->attributes, 0, sizeof(Icc ->attributes)); + Icc ->RenderingIntent = 0; + memset(&Icc ->ProfileID, 0, sizeof(Icc ->ProfileID)); + + // Compute needed storage + if (!cmsSaveProfileToMem(hProfile, NULL, &BytesNeeded)) goto Error; + + // Allocate memory + Mem = (cmsUInt8Number*) _cmsMalloc(ContextID, BytesNeeded); + if (Mem == NULL) goto Error; + + // Save to temporary storage + if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error; + + // Create MD5 object + MD5 = MD5alloc(ContextID); + if (MD5 == NULL) goto Error; + + // Add all bytes + MD5add(MD5, Mem, BytesNeeded); + + // Temp storage is no longer needed + _cmsFree(ContextID, Mem); + + // Restore header + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + + // And store the ID + MD5finish(&Icc ->ProfileID, MD5); + return TRUE; + +Error: + + // Free resources as something went wrong + if (MD5 != NULL) _cmsFree(ContextID, MD5); + if (Mem != NULL) _cmsFree(ContextID, Mem); + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + return FALSE; +} + diff --git a/thirdparty/liblcms2/src/cmsmtrx.c b/thirdparty/liblcms2/src/cmsmtrx.c new file mode 100644 index 00000000..84035c93 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsmtrx.c @@ -0,0 +1,176 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +#define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;} + + +// Initiate a vector +void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z) +{ + r -> n[VX] = x; + r -> n[VY] = y; + r -> n[VZ] = z; +} + +// Vector substraction +void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b) +{ + r -> n[VX] = a -> n[VX] - b -> n[VX]; + r -> n[VY] = a -> n[VY] - b -> n[VY]; + r -> n[VZ] = a -> n[VZ] - b -> n[VZ]; +} + +// Vector cross product +void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v) +{ + r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ]; + r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX]; + r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY]; +} + +// Vector dot product +cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v) +{ + return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ]; +} + +// Euclidean length +cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a) +{ + return sqrt(a ->n[VX] * a ->n[VX] + + a ->n[VY] * a ->n[VY] + + a ->n[VZ] * a ->n[VZ]); +} + +// Euclidean distance +cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b) +{ + cmsFloat64Number d1 = a ->n[VX] - b ->n[VX]; + cmsFloat64Number d2 = a ->n[VY] - b ->n[VY]; + cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ]; + + return sqrt(d1*d1 + d2*d2 + d3*d3); +} + + + +// 3x3 Identity +void CMSEXPORT _cmsMAT3identity(cmsMAT3* a) +{ + _cmsVEC3init(&a-> v[0], 1.0, 0.0, 0.0); + _cmsVEC3init(&a-> v[1], 0.0, 1.0, 0.0); + _cmsVEC3init(&a-> v[2], 0.0, 0.0, 1.0); +} + +static +cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) +{ + return fabs(b - a) < (1.0 / 65535.0); +} + + +cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a) +{ + cmsMAT3 Identity; + int i, j; + + _cmsMAT3identity(&Identity); + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE; + + return TRUE; +} + + +// Multiply two matrices +void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b) +{ +#define ROWCOL(i, j) \ + a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j] + + _cmsVEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)); + _cmsVEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)); + _cmsVEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2)); + +#undef ROWCOL //(i, j) +} + + + +// Inverse of a matrix b = a^(-1) +cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b) +{ + cmsFloat64Number det, c0, c1, c2; + + c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1]; + c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0]; + c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0]; + + det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2; + + if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert + + b -> v[0].n[0] = c0/det; + b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det; + b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det; + b -> v[1].n[0] = c1/det; + b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det; + b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det; + b -> v[2].n[0] = c2/det; + b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det; + b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det; + + return TRUE; +} + + +// Solve a system in the form Ax = b +cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b) +{ + cmsMAT3 m, a_1; + + memmove(&m, a, sizeof(cmsMAT3)); + + if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix + + _cmsMAT3eval(x, &a_1, b); + return TRUE; +} + +// Evaluate a vector across a matrix +void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v) +{ + r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ]; + r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ]; + r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ]; +} + + diff --git a/thirdparty/liblcms2/src/cmsnamed.c b/thirdparty/liblcms2/src/cmsnamed.c new file mode 100644 index 00000000..d1a86b6e --- /dev/null +++ b/thirdparty/liblcms2/src/cmsnamed.c @@ -0,0 +1,750 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Multilocalized unicode objects. That is an attempt to encapsulate i18n. + + +// Allocates an empty multi localizad unicode object +cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems) +{ + cmsMLU* mlu; + + // nItems should be positive if given + if (nItems <= 0) nItems = 2; + + // Create the container + mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); + if (mlu == NULL) return NULL; + + mlu ->ContextID = ContextID; + + // Create entry array + mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); + if (mlu ->Entries == NULL) { + _cmsFree(ContextID, mlu); + return NULL; + } + + // Ok, keep indexes up to date + mlu ->AllocatedEntries = nItems; + mlu ->UsedEntries = 0; + + return mlu; +} + + +// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. +static +cmsBool GrowMLUpool(cmsMLU* mlu) +{ + cmsUInt32Number size; + void *NewPtr; + + // Sanity check + if (mlu == NULL) return FALSE; + + if (mlu ->PoolSize == 0) + size = 256; + else + size = mlu ->PoolSize * 2; + + // Check for overflow + if (size < mlu ->PoolSize) return FALSE; + + // Reallocate the pool + NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size); + if (NewPtr == NULL) return FALSE; + + + mlu ->MemPool = NewPtr; + mlu ->PoolSize = size; + + return TRUE; +} + + +// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two. +static +cmsBool GrowMLUtable(cmsMLU* mlu) +{ + int AllocatedEntries; + _cmsMLUentry *NewPtr; + + // Sanity check + if (mlu == NULL) return FALSE; + + AllocatedEntries = mlu ->AllocatedEntries * 2; + + // Check for overflow + if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; + + // Reallocate the memory + NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); + if (NewPtr == NULL) return FALSE; + + mlu ->Entries = NewPtr; + mlu ->AllocatedEntries = AllocatedEntries; + + return TRUE; +} + + +// Search for a specific entry in the structure. Language and Country are used. +static +int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) +{ + int i; + + // Sanity check + if (mlu == NULL) return -1; + + // Iterate whole table + for (i=0; i < mlu ->UsedEntries; i++) { + + if (mlu ->Entries[i].Country == CountryCode && + mlu ->Entries[i].Language == LanguageCode) return i; + } + + // Not found + return -1; +} + +// Add a block of characters to the intended MLU. Language and country are specified. +// Only one entry for Language/country pair is allowed. +static +cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, + cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) +{ + cmsUInt32Number Offset; + cmsUInt8Number* Ptr; + + // Sanity check + if (mlu == NULL) return FALSE; + + // Is there any room available? + if (mlu ->UsedEntries >= mlu ->AllocatedEntries) { + if (!GrowMLUtable(mlu)) return FALSE; + } + + // Only one ASCII string + if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed! + + // Check for size + while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { + + if (!GrowMLUpool(mlu)) return FALSE; + } + + Offset = mlu ->PoolUsed; + + Ptr = (cmsUInt8Number*) mlu ->MemPool; + if (Ptr == NULL) return FALSE; + + // Set the entry + memmove(Ptr + Offset, Block, size); + mlu ->PoolUsed += size; + + mlu ->Entries[mlu ->UsedEntries].StrW = Offset; + mlu ->Entries[mlu ->UsedEntries].Len = size; + mlu ->Entries[mlu ->UsedEntries].Country = CountryCode; + mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode; + mlu ->UsedEntries++; + + return TRUE; +} + + +// Add an ASCII entry. +cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) +{ + cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1; + wchar_t* WStr; + cmsBool rc; + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + + if (mlu == NULL) return FALSE; + + WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); + if (WStr == NULL) return FALSE; + + for (i=0; i < len; i++) + WStr[i] = (wchar_t) ASCIIString[i]; + + rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); + + _cmsFree(mlu ->ContextID, WStr); + return rc; + +} + +// We don't need any wcs support library +static +cmsUInt32Number mywcslen(const wchar_t *s) +{ + const wchar_t *p; + + p = s; + while (*p) + p++; + + return (cmsUInt32Number)(p - s); +} + + +// Add a wide entry +cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString) +{ + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language); + cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country); + cmsUInt32Number len; + + if (mlu == NULL) return FALSE; + if (WideString == NULL) return FALSE; + + len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t); + return AddMLUBlock(mlu, len, WideString, Lang, Cntry); +} + +// Duplicating a MLU is as easy as copying all members +cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu) +{ + cmsMLU* NewMlu = NULL; + + // Duplicating a NULL obtains a NULL + if (mlu == NULL) return NULL; + + NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries); + if (NewMlu == NULL) return NULL; + + // Should never happen + if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) + goto Error; + + // Sanitize... + if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; + + memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); + NewMlu ->UsedEntries = mlu ->UsedEntries; + + // The MLU may be empty + if (mlu ->PoolUsed == 0) { + NewMlu ->MemPool = NULL; + } + else { + // It is not empty + NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed); + if (NewMlu ->MemPool == NULL) goto Error; + } + + NewMlu ->PoolSize = mlu ->PoolUsed; + + if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; + + memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); + NewMlu ->PoolUsed = mlu ->PoolUsed; + + return NewMlu; + +Error: + + if (NewMlu != NULL) cmsMLUfree(NewMlu); + return NULL; +} + +// Free any used memory +void CMSEXPORT cmsMLUfree(cmsMLU* mlu) +{ + if (mlu) { + + if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries); + if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool); + + _cmsFree(mlu ->ContextID, mlu); + } +} + + +// The algorithm first searches for an exact match of country and language, if not found it uses +// the Language. If none is found, first entry is used instead. +static +const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, + cmsUInt32Number *len, + cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, + cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) +{ + int i; + int Best = -1; + _cmsMLUentry* v; + + if (mlu == NULL) return NULL; + + if (mlu -> AllocatedEntries <= 0) return NULL; + + for (i=0; i < mlu ->UsedEntries; i++) { + + v = mlu ->Entries + i; + + if (v -> Language == LanguageCode) { + + if (Best == -1) Best = i; + + if (v -> Country == CountryCode) { + + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; + + if (len != NULL) *len = v ->Len; + + return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match + } + } + } + + // No string found. Return First one + if (Best == -1) + Best = 0; + + v = mlu ->Entries + Best; + + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; + + if (len != NULL) *len = v ->Len; + + return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); +} + + +// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len +cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const wchar_t *Wide; + cmsUInt32Number StrLen = 0; + cmsUInt32Number ASCIIlen, i; + + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + + // Sanitize + if (mlu == NULL) return 0; + + // Get WideChar + Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); + if (Wide == NULL) return 0; + + ASCIIlen = StrLen / sizeof(wchar_t); + + // Maybe we want only to know the len? + if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end + + // No buffer size means no data + if (BufferSize <= 0) return 0; + + // Some clipping may be required + if (BufferSize < ASCIIlen + 1) + ASCIIlen = BufferSize - 1; + + // Precess each character + for (i=0; i < ASCIIlen; i++) { + + if (Wide[i] == 0) + Buffer[i] = 0; + else + Buffer[i] = (char) Wide[i]; + } + + // We put a termination "\0" + Buffer[ASCIIlen] = 0; + return ASCIIlen + 1; +} + +// Obtain a wide representation of the MLU, on depending on current locale settings +cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize) +{ + const wchar_t *Wide; + cmsUInt32Number StrLen = 0; + + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + + // Sanitize + if (mlu == NULL) return 0; + + Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); + if (Wide == NULL) return 0; + + // Maybe we want only to know the len? + if (Buffer == NULL) return StrLen + sizeof(wchar_t); + + // No buffer size means no data + if (BufferSize <= 0) return 0; + + // Some clipping may be required + if (BufferSize < StrLen + sizeof(wchar_t)) + StrLen = BufferSize - + sizeof(wchar_t); + + memmove(Buffer, Wide, StrLen); + Buffer[StrLen / sizeof(wchar_t)] = 0; + + return StrLen + sizeof(wchar_t); +} + + +// Get also the language and country +CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char ObtainedLanguage[3], char ObtainedCountry[3]) +{ + const wchar_t *Wide; + + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + cmsUInt16Number ObtLang, ObtCode; + + // Sanitize + if (mlu == NULL) return FALSE; + + Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode); + if (Wide == NULL) return FALSE; + + // Get used language and code + *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang); + *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode); + + ObtainedLanguage[2] = ObtainedCountry[2] = 0; + return TRUE; +} + + +// Named color lists -------------------------------------------------------------------------------------------- + +// Grow the list to keep at least NumElements +static +cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) +{ + cmsUInt32Number size; + _cmsNAMEDCOLOR * NewPtr; + + if (v == NULL) return FALSE; + + if (v ->Allocated == 0) + size = 64; // Initial guess + else + size = v ->Allocated * 2; + + // Keep a maximum color lists can grow, 100K entries seems reasonable + if (size > 1024*100) return FALSE; + + NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); + if (NewPtr == NULL) + return FALSE; + + v ->List = NewPtr; + v ->Allocated = size; + return TRUE; +} + +// Allocate a list for n elements +cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix) +{ + cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST)); + + if (v == NULL) return NULL; + + v ->List = NULL; + v ->nColors = 0; + v ->ContextID = ContextID; + + while (v -> Allocated < n) + GrowNamedColorList(v); + + strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)); + strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)); + v -> ColorantCount = ColorantCount; + + return v; +} + +// Free a list +void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) +{ + if (v ->List) _cmsFree(v ->ContextID, v ->List); + if (v) _cmsFree(v ->ContextID, v); +} + +cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) +{ + cmsNAMEDCOLORLIST* NewNC; + + if (v == NULL) return NULL; + + NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix); + if (NewNC == NULL) return NULL; + + // For really large tables we need this + while (NewNC ->Allocated < v ->Allocated) + GrowNamedColorList(NewNC); + + memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); + memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix)); + NewNC ->ColorantCount = v ->ColorantCount; + memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR)); + NewNC ->nColors = v ->nColors; + return NewNC; +} + + +// Append a color to a list. List pointer may change if reallocated +cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, + const char* Name, + cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS]) +{ + cmsUInt32Number i; + + if (NamedColorList == NULL) return FALSE; + + if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) { + if (!GrowNamedColorList(NamedColorList)) return FALSE; + } + + for (i=0; i < NamedColorList ->ColorantCount; i++) + NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i]; + + for (i=0; i < 3; i++) + NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i]; + + if (Name != NULL) + strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, + sizeof(NamedColorList ->List[NamedColorList ->nColors].Name)); + else + NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; + + + NamedColorList ->nColors++; + return TRUE; +} + +// Returns number of elements +cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList) +{ + if (NamedColorList == NULL) return 0; + return NamedColorList ->nColors; +} + +// Info aboout a given color +cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, + char* Name, + char* Prefix, + char* Suffix, + cmsUInt16Number* PCS, + cmsUInt16Number* Colorant) +{ + if (NamedColorList == NULL) return FALSE; + + if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE; + + if (Name) strcpy(Name, NamedColorList->List[nColor].Name); + if (Prefix) strcpy(Prefix, NamedColorList->Prefix); + if (Suffix) strcpy(Suffix, NamedColorList->Suffix); + if (PCS) + memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); + + if (Colorant) + memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, + sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); + + + return TRUE; +} + +// Search for a given color name (no prefix or suffix) +cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name) +{ + int i, n; + + if (NamedColorList == NULL) return -1; + n = cmsNamedColorCount(NamedColorList); + for (i=0; i < n; i++) { + if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0) + return i; + } + + return -1; +} + +// MPE support ----------------------------------------------------------------------------------------------------------------- + +static +void FreeNamedColorList(cmsStage* mpe) +{ + cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; + cmsFreeNamedColorList(List); +} + +static +void* DupNamedColorList(cmsStage* mpe) +{ + cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; + return cmsDupNamedColorList(List); +} + +static +void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; + cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); + cmsUInt32Number j; + + if (index >= NamedColorList-> nColors) { + cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); + } + else { + for (j=0; j < NamedColorList ->ColorantCount; j++) + Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); + } +} + + +// Named color lookup element +cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList) +{ + return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, + cmsSigNamedColorElemType, + 1, 3, + EvalNamedColor, + DupNamedColorList, + FreeNamedColorList, + cmsDupNamedColorList(NamedColorList)); + +} + + +// Retrieve the named color list from a transform. Should be first element in the LUT +cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) +{ + _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; + cmsStage* mpe = v ->Lut->Elements; + + if (mpe ->Type != cmsSigNamedColorElemType) return NULL; + return (cmsNAMEDCOLORLIST*) mpe ->Data; +} + + +// Profile sequence description routines ------------------------------------------------------------------------------------- + +cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n) +{ + cmsSEQ* Seq; + cmsUInt32Number i; + + if (n == 0) return NULL; + + // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked + // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door! + if (n > 255) return NULL; + + Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ)); + if (Seq == NULL) return NULL; + + Seq -> ContextID = ContextID; + Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC)); + Seq -> n = n; + + + for (i=0; i < n; i++) { + Seq -> seq[i].Manufacturer = NULL; + Seq -> seq[i].Model = NULL; + Seq -> seq[i].Description = NULL; + } + + return Seq; +} + +void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) +{ + cmsUInt32Number i; + + for (i=0; i < pseq ->n; i++) { + if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); + if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); + if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); + } + + if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); + _cmsFree(pseq -> ContextID, pseq); +} + +cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq) +{ + cmsSEQ *NewSeq; + cmsUInt32Number i; + + if (pseq == NULL) + return NULL; + + NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ)); + if (NewSeq == NULL) return NULL; + + + NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC)); + if (NewSeq ->seq == NULL) goto Error; + + NewSeq -> ContextID = pseq ->ContextID; + NewSeq -> n = pseq ->n; + + for (i=0; i < pseq->n; i++) { + + memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number)); + + NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg; + NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel; + memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID)); + NewSeq ->seq[i].technology = pseq ->seq[i].technology; + + NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer); + NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model); + NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description); + + } + + return NewSeq; + +Error: + + cmsFreeProfileSequenceDescription(NewSeq); + return NULL; +} + + + + diff --git a/thirdparty/liblcms2/src/cmsopt.c b/thirdparty/liblcms2/src/cmsopt.c new file mode 100644 index 00000000..b1ce98e3 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsopt.c @@ -0,0 +1,1631 @@ + +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +//---------------------------------------------------------------------------------- + +// Optimization for 8 bits, Shaper-CLUT (3 inputs only) +typedef struct { + + cmsContext ContextID; + + const cmsInterpParams* p; // Tetrahedrical interpolation parameters. This is a not-owned pointer. + + cmsUInt16Number rx[256], ry[256], rz[256]; + cmsUInt32Number X0[256], Y0[256], Z0[256]; // Precomputed nodes and offsets for 8-bit input data + + +} Prelin8Data; + + +// Generic optimization for 16 bits Shaper-CLUT-Shaper (any inputs) +typedef struct { + + cmsContext ContextID; + + // Number of channels + int nInputs; + int nOutputs; + + // Since there is no limitation of the output number of channels, this buffer holding the connexion CLUT-shaper + // has to be dynamically allocated. This is not the case of first step shaper-CLUT, which is limited to max inputs + cmsUInt16Number* StageDEF; + + _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance + cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; + + _cmsInterpFn16 EvalCLUT; // The evaluator for 3D grid + const cmsInterpParams* CLUTparams; // (not-owned pointer) + + + _cmsInterpFn16* EvalCurveOut16; // Points to an array of curve evaluators in 16 bits (not-owned pointer) + cmsInterpParams** ParamsCurveOut16; // Points to an array of references to interpolation params (not-owned pointer) + + +} Prelin16Data; + + +// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed + +typedef cmsInt32Number cmsS1Fixed14Number; // Note that this may hold more than 16 bits! + +#define DOUBLE_TO_1FIXED14(x) ((cmsS1Fixed14Number) floor((x) * 16384.0 + 0.5)) + +typedef struct { + + cmsContext ContextID; + + cmsS1Fixed14Number Shaper1R[256]; // from 0..255 to 1.14 (0.0...1.0) + cmsS1Fixed14Number Shaper1G[256]; + cmsS1Fixed14Number Shaper1B[256]; + + cmsS1Fixed14Number Mat[3][3]; // n.14 to n.14 (needs a saturation after that) + cmsS1Fixed14Number Off[3]; + + cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255 + cmsUInt16Number Shaper2G[16385]; + cmsUInt16Number Shaper2B[16385]; + +} MatShaper8Data; + +// Curves, optimization is shared between 8 and 16 bits +typedef struct { + + cmsContext ContextID; + + int nCurves; // Number of curves + int nElements; // Elements in curves + cmsUInt16Number** Curves; // Points to a dynamically allocated array + +} Curves16Data; + + +// Simple optimizations ---------------------------------------------------------------------------------------------------------- + + +// Remove an element in linked chain +static +void _RemoveElement(cmsStage** head) +{ + cmsStage* mpe = *head; + cmsStage* next = mpe ->Next; + *head = next; + cmsStageFree(mpe); +} + +// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer. +static +cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) +{ + cmsStage** pt = &Lut ->Elements; + cmsBool AnyOpt = FALSE; + + while (*pt != NULL) { + + if ((*pt) ->Implements == UnaryOp) { + _RemoveElement(pt); + AnyOpt = TRUE; + } + else + pt = &((*pt) -> Next); + } + + return AnyOpt; +} + +// Same, but only if two adjacent elements are found +static +cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op2) +{ + cmsStage** pt1; + cmsStage** pt2; + cmsBool AnyOpt = FALSE; + + pt1 = &Lut ->Elements; + if (*pt1 == NULL) return AnyOpt; + + while (*pt1 != NULL) { + + pt2 = &((*pt1) -> Next); + if (*pt2 == NULL) return AnyOpt; + + if ((*pt1) ->Implements == Op1 && (*pt2) ->Implements == Op2) { + _RemoveElement(pt2); + _RemoveElement(pt1); + AnyOpt = TRUE; + } + else + pt1 = &((*pt1) -> Next); + } + + return AnyOpt; +} + +// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed +// by a v4 to v2 and vice-versa. The elements are then discarded. +static +cmsBool PreOptimize(cmsPipeline* Lut) +{ + cmsBool AnyOpt = FALSE, Opt; + + AnyOpt = FALSE; + + do { + + Opt = FALSE; + + // Remove all identities + Opt |= _Remove1Op(Lut, cmsSigIdentityElemType); + + // Remove XYZ2Lab followed by Lab2XYZ + Opt |= _Remove2Op(Lut, cmsSigXYZ2LabElemType, cmsSigLab2XYZElemType); + + // Remove Lab2XYZ followed by XYZ2Lab + Opt |= _Remove2Op(Lut, cmsSigLab2XYZElemType, cmsSigXYZ2LabElemType); + + // Remove V4 to V2 followed by V2 to V4 + Opt |= _Remove2Op(Lut, cmsSigLabV4toV2, cmsSigLabV2toV4); + + // Remove V2 to V4 followed by V4 to V2 + Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2); + + if (Opt) AnyOpt = TRUE; + + } while (Opt); + + return AnyOpt; +} + +static +void Eval16nop1D(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const struct _cms_interp_struc* p) +{ + Output[0] = Input[0]; + + cmsUNUSED_PARAMETER(p); +} + +static +void PrelinEval16(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const void* D) +{ + Prelin16Data* p16 = (Prelin16Data*) D; + cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; + int i; + + for (i=0; i < p16 ->nInputs; i++) { + + p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); + } + + p16 ->EvalCLUT(StageABC, p16 ->StageDEF, p16 ->CLUTparams); + + for (i=0; i < p16 ->nOutputs; i++) { + + p16 ->EvalCurveOut16[i](&p16->StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); + } +} + + +static +void PrelinOpt16free(cmsContext ContextID, void* ptr) +{ + Prelin16Data* p16 = (Prelin16Data*) ptr; + + _cmsFree(ContextID, p16 ->StageDEF); + _cmsFree(ContextID, p16 ->EvalCurveOut16); + _cmsFree(ContextID, p16 ->ParamsCurveOut16); + + _cmsFree(ContextID, p16); +} + +static +void* Prelin16dup(cmsContext ContextID, const void* ptr) +{ + Prelin16Data* p16 = (Prelin16Data*) ptr; + Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); + + if (Duped == NULL) return NULL; + + Duped ->StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number)); + Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); + Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); + + return Duped; +} + + +static +Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, + const cmsInterpParams* ColorMap, + int nInputs, cmsToneCurve** In, + int nOutputs, cmsToneCurve** Out ) +{ + int i; + Prelin16Data* p16 = (Prelin16Data*) _cmsMallocZero(ContextID, sizeof(Prelin16Data)); + if (p16 == NULL) return NULL; + + p16 ->nInputs = nInputs; + p16 -> nOutputs = nOutputs; + + + for (i=0; i < nInputs; i++) { + + if (In == NULL) { + p16 -> ParamsCurveIn16[i] = NULL; + p16 -> EvalCurveIn16[i] = Eval16nop1D; + + } + else { + p16 -> ParamsCurveIn16[i] = In[i] ->InterpParams; + p16 -> EvalCurveIn16[i] = p16 ->ParamsCurveIn16[i]->Interpolation.Lerp16; + } + } + + p16 ->CLUTparams = ColorMap; + p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; + + + p16 -> StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number)); + p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); + p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); + + for (i=0; i < nOutputs; i++) { + + if (Out == NULL) { + p16 ->ParamsCurveOut16[i] = NULL; + p16 -> EvalCurveOut16[i] = Eval16nop1D; + } + else { + + p16 ->ParamsCurveOut16[i] = Out[i] ->InterpParams; + p16 -> EvalCurveOut16[i] = p16 ->ParamsCurveOut16[i]->Interpolation.Lerp16; + } + } + + return p16; +} + + + +// Resampling --------------------------------------------------------------------------------- + +#define PRELINEARIZATION_POINTS 4096 + +// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for +// almost any transform. We use floating point precision and then convert from floating point to 16 bits. +static +int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + cmsPipeline* Lut = (cmsPipeline*) Cargo; + cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; + cmsUInt32Number i; + + _cmsAssert(Lut -> InputChannels < cmsMAXCHANNELS); + _cmsAssert(Lut -> OutputChannels < cmsMAXCHANNELS); + + // From 16 bit to floating point + for (i=0; i < Lut ->InputChannels; i++) + InFloat[i] = (cmsFloat32Number) (In[i] / 65535.0); + + // Evaluate in floating point + cmsPipelineEvalFloat(InFloat, OutFloat, Lut); + + // Back to 16 bits representation + for (i=0; i < Lut ->OutputChannels; i++) + Out[i] = _cmsQuickSaturateWord(OutFloat[i] * 65535.0); + + // Always succeed + return TRUE; +} + +// Try to see if the curves of a given MPE are linear +static +cmsBool AllCurvesAreLinear(cmsStage* mpe) +{ + cmsToneCurve** Curves; + cmsUInt32Number i, n; + + Curves = _cmsStageGetPtrToCurveSet(mpe); + if (Curves == NULL) return FALSE; + + n = cmsStageOutputChannels(mpe); + + for (i=0; i < n; i++) { + if (!cmsIsToneCurveLinear(Curves[i])) return FALSE; + } + + return TRUE; +} + +// This function replaces a specific node placed in "At" by the "Value" numbers. Its purpose +// is to fix scum dot on broken profiles/transforms. Works on 1, 3 and 4 channels +static +cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], + int nChannelsOut, int nChannelsIn) +{ + _cmsStageCLutData* Grid = (_cmsStageCLutData*) CLUT ->Data; + cmsInterpParams* p16 = Grid ->Params; + cmsFloat64Number px, py, pz, pw; + int x0, y0, z0, w0; + int i, index; + + if (CLUT -> Type != cmsSigCLutElemType) { + cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut MPE"); + return FALSE; + } + + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; + pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; + pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0; + + x0 = (int) floor(px); + y0 = (int) floor(py); + z0 = (int) floor(pz); + w0 = (int) floor(pw); + + if (nChannelsIn == 4) { + + if (((px - x0) != 0) || + ((py - y0) != 0) || + ((pz - z0) != 0) || + ((pw - w0) != 0)) return FALSE; // Not on exact node + + index = p16 -> opta[3] * x0 + + p16 -> opta[2] * y0 + + p16 -> opta[1] * z0 + + p16 -> opta[0] * w0; + } + else + if (nChannelsIn == 3) { + + if (((px - x0) != 0) || + ((py - y0) != 0) || + ((pz - z0) != 0)) return FALSE; // Not on exact node + + index = p16 -> opta[2] * x0 + + p16 -> opta[1] * y0 + + p16 -> opta[0] * z0; + } + else + if (nChannelsIn == 1) { + + if (((px - x0) != 0)) return FALSE; // Not on exact node + + index = p16 -> opta[0] * x0; + } + else { + cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); + return FALSE; + } + + for (i=0; i < nChannelsOut; i++) + Grid -> Tab.T[index + i] = Value[i]; + + return TRUE; +} + +// Auxiliar, to see if two values are equal. +static +cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) +{ + int i; + + for (i=0; i < n; i++) { + if (White1[i] != White2[i]) return FALSE; + } + return TRUE; +} + + +// Locate the node for the white point and fix it to pure white in order to avoid scum dot. +static +cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColorSpace, cmsColorSpaceSignature ExitColorSpace) +{ + cmsUInt16Number *WhitePointIn, *WhitePointOut; + cmsUInt16Number WhiteIn[cmsMAXCHANNELS], WhiteOut[cmsMAXCHANNELS], ObtainedOut[cmsMAXCHANNELS]; + cmsUInt32Number i, nOuts, nIns; + cmsStage *PreLin = NULL, *CLUT = NULL, *PostLin = NULL; + + if (!_cmsEndPointsBySpace(EntryColorSpace, + &WhitePointIn, NULL, &nIns)) return FALSE; + + if (!_cmsEndPointsBySpace(ExitColorSpace, + &WhitePointOut, NULL, &nOuts)) return FALSE; + + // It needs to be fixed? + + cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut); + + if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match + + // Check if the LUT comes as Prelin, CLUT or Postlin. We allow all combinations + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &PreLin, &CLUT, &PostLin)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCurveSetElemType, cmsSigCLutElemType, &PreLin, &CLUT)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCLutElemType, cmsSigCurveSetElemType, &CLUT, &PostLin)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCLutElemType, &CLUT)) + return FALSE; + + // We need to interpolate white points of both, pre and post curves + if (PreLin) { + + cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PreLin); + + for (i=0; i < nIns; i++) { + WhiteIn[i] = cmsEvalToneCurve16(Curves[i], WhitePointIn[i]); + } + } + else { + for (i=0; i < nIns; i++) + WhiteIn[i] = WhitePointIn[i]; + } + + // If any post-linearization, we need to find how is represented white before the curve, do + // a reverse interpolation in this case. + if (PostLin) { + + cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PostLin); + + for (i=0; i < nOuts; i++) { + + cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); + WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); + cmsFreeToneCurve(InversePostLin); + } + } + else { + for (i=0; i < nOuts; i++) + WhiteOut[i] = WhitePointOut[i]; + } + + // Ok, proceed with patching. May fail and we don't care if it fails + PatchLUT(CLUT, WhiteIn, WhiteOut, nOuts, nIns); + + return TRUE; +} + +// ----------------------------------------------------------------------------------------------------------------------------------------------- +// This function creates simple LUT from complex ones. The generated LUT has an optional set of +// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables. +// These curves have to exist in the original LUT in order to be used in the simplified output. +// Caller may also use the flags to allow this feature. +// LUTS with all curves will be simplified to a single curve. Parametric curves are lost. +// This function should be used on 16-bits LUTS only, as floating point losses precision when simplified +// ----------------------------------------------------------------------------------------------------------------------------------------------- + +static +cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsPipeline* Src; + cmsPipeline* Dest; + cmsStage* CLUT; + cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; + int nGridPoints; + cmsColorSpaceSignature ColorSpace, OutputColorSpace; + cmsStage *NewPreLin = NULL; + cmsStage *NewPostLin = NULL; + _cmsStageCLutData* DataCLUT; + cmsToneCurve** DataSetIn; + cmsToneCurve** DataSetOut; + Prelin16Data* p16; + + + // This is a loosy optimization! does not apply in floating-point cases + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; + + ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); + OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); + nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); + + // For empty LUTs, 2 points are enough + if (cmsPipelineStageCount(*Lut) == 0) + nGridPoints = 2; + + Src = *Lut; + + // Allocate an empty LUT + Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); + if (!Dest) return FALSE; + + // Prelinearization tables are kept unless indicated by flags + if (*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION) { + + // Get a pointer to the prelinearization element + cmsStage* PreLin = cmsPipelineGetPtrToFirstStage(Src); + + // Check if suitable + if (PreLin ->Type == cmsSigCurveSetElemType) { + + // Maybe this is a linear tram, so we can avoid the whole stuff + if (!AllCurvesAreLinear(PreLin)) { + + // All seems ok, proceed. + NewPreLin = cmsStageDup(PreLin); + cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin); + + // Remove prelinearization. Since we have duplicated the curve + // in destination LUT, the sampling shoud be applied after this stage. + cmsPipelineUnlinkStage(Src, cmsAT_BEGIN, &KeepPreLin); + } + } + } + + // Allocate the CLUT + CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL); + if (CLUT == NULL) return FALSE; + + // Add the CLUT to the destination LUT + cmsPipelineInsertStage(Dest, cmsAT_END, CLUT); + + // Postlinearization tables are kept unless indicated by flags + if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { + + // Get a pointer to the postlinearization if present + cmsStage* PostLin = cmsPipelineGetPtrToLastStage(Src); + + // Check if suitable + if (cmsStageType(PostLin) == cmsSigCurveSetElemType) { + + // Maybe this is a linear tram, so we can avoid the whole stuff + if (!AllCurvesAreLinear(PostLin)) { + + // All seems ok, proceed. + NewPostLin = cmsStageDup(PostLin); + cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin); + + // In destination LUT, the sampling shoud be applied after this stage. + cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); + } + } + } + + // Now its time to do the sampling. We have to ignore pre/post linearization + // The source LUT whithout pre/post curves is passed as parameter. + if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { + + // Ops, something went wrong, Restore stages + if (KeepPreLin != NULL) cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin); + if (KeepPostLin != NULL) cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin); + cmsPipelineFree(Dest); + return FALSE; + } + + // Done. + + if (KeepPreLin != NULL) cmsStageFree(KeepPreLin); + if (KeepPostLin != NULL) cmsStageFree(KeepPostLin); + cmsPipelineFree(Src); + + DataCLUT = (_cmsStageCLutData*) CLUT ->Data; + + if (NewPreLin == NULL) DataSetIn = NULL; + else DataSetIn = ((_cmsStageToneCurvesData*) NewPreLin ->Data) ->TheCurves; + + if (NewPostLin == NULL) DataSetOut = NULL; + else DataSetOut = ((_cmsStageToneCurvesData*) NewPostLin ->Data) ->TheCurves; + + + if (DataSetIn == NULL && DataSetOut == NULL) { + + _cmsPipelineSetOptimizationParameters(Dest, (_cmsOPTeval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL); + } + else { + + p16 = PrelinOpt16alloc(Dest ->ContextID, + DataCLUT ->Params, + Dest ->InputChannels, + DataSetIn, + Dest ->OutputChannels, + DataSetOut); + + + _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); + } + + + // Don't fix white on absolute colorimetric + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; + + if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { + + FixWhiteMisalignment(Dest, ColorSpace, OutputColorSpace); + } + + *Lut = Dest; + return TRUE; + + cmsUNUSED_PARAMETER(Intent); +} + + +// ----------------------------------------------------------------------------------------------------------------------------------------------- +// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on +// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works +// for RGB transforms. See the paper for more details +// ----------------------------------------------------------------------------------------------------------------------------------------------- + + +// Normalize endpoints by slope limiting max and min. This assures endpoints as well. +// Descending curves are handled as well. +static +void SlopeLimiting(cmsToneCurve* g) +{ + int BeginVal, EndVal; + int AtBegin = (int) floor((cmsFloat64Number) g ->nEntries * 0.02 + 0.5); // Cutoff at 2% + int AtEnd = g ->nEntries - AtBegin - 1; // And 98% + cmsFloat64Number Val, Slope, beta; + int i; + + if (cmsIsToneCurveDescending(g)) { + BeginVal = 0xffff; EndVal = 0; + } + else { + BeginVal = 0; EndVal = 0xffff; + } + + // Compute slope and offset for begin of curve + Val = g ->Table16[AtBegin]; + Slope = (Val - BeginVal) / AtBegin; + beta = Val - Slope * AtBegin; + + for (i=0; i < AtBegin; i++) + g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); + + // Compute slope and offset for the end + Val = g ->Table16[AtEnd]; + Slope = (EndVal - Val) / AtBegin; // AtBegin holds the X interval, which is same in both cases + beta = Val - Slope * AtEnd; + + for (i = AtEnd; i < (int) g ->nEntries; i++) + g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); +} + + +// Precomputes tables for 8-bit on input devicelink. +static +Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cmsToneCurve* G[3]) +{ + int i; + cmsUInt16Number Input[3]; + cmsS15Fixed16Number v1, v2, v3; + Prelin8Data* p8; + + p8 = _cmsMallocZero(ContextID, sizeof(Prelin8Data)); + if (p8 == NULL) return NULL; + + // Since this only works for 8 bit input, values comes always as x * 257, + // we can safely take msb byte (x << 8 + x) + + for (i=0; i < 256; i++) { + + if (G != NULL) { + + // Get 16-bit representation + Input[0] = cmsEvalToneCurve16(G[0], FROM_8_TO_16(i)); + Input[1] = cmsEvalToneCurve16(G[1], FROM_8_TO_16(i)); + Input[2] = cmsEvalToneCurve16(G[2], FROM_8_TO_16(i)); + } + else { + Input[0] = FROM_8_TO_16(i); + Input[1] = FROM_8_TO_16(i); + Input[2] = FROM_8_TO_16(i); + } + + + // Move to 0..1.0 in fixed domain + v1 = _cmsToFixedDomain(Input[0] * p -> Domain[0]); + v2 = _cmsToFixedDomain(Input[1] * p -> Domain[1]); + v3 = _cmsToFixedDomain(Input[2] * p -> Domain[2]); + + // Store the precalculated table of nodes + p8 ->X0[i] = (p->opta[2] * FIXED_TO_INT(v1)); + p8 ->Y0[i] = (p->opta[1] * FIXED_TO_INT(v2)); + p8 ->Z0[i] = (p->opta[0] * FIXED_TO_INT(v3)); + + // Store the precalculated table of offsets + p8 ->rx[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v1); + p8 ->ry[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v2); + p8 ->rz[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v3); + } + + p8 ->ContextID = ContextID; + p8 ->p = p; + + return p8; +} + +static +void Prelin8free(cmsContext ContextID, void* ptr) +{ + _cmsFree(ContextID, ptr); +} + +static +void* Prelin8dup(cmsContext ContextID, const void* ptr) +{ + return _cmsDupMem(ContextID, ptr, sizeof(Prelin8Data)); +} + + + +// A optimized interpolation for 8-bit input. +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +static +void PrelinEval8(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const void* D) +{ + + cmsUInt8Number r, g, b; + cmsS15Fixed16Number rx, ry, rz; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + int OutChan; + register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + Prelin8Data* p8 = (Prelin8Data*) D; + register const cmsInterpParams* p = p8 ->p; + int TotalOut = p -> nOutputs; + const cmsUInt16Number* LutTable = p -> Table; + + r = Input[0] >> 8; + g = Input[1] >> 8; + b = Input[2] >> 8; + + X0 = X1 = p8->X0[r]; + Y0 = Y1 = p8->Y0[g]; + Z0 = Z1 = p8->Z0[b]; + + rx = p8 ->rx[r]; + ry = p8 ->ry[g]; + rz = p8 ->rz[b]; + + X1 = X0 + ((rx == 0) ? 0 : p ->opta[2]); + Y1 = Y0 + ((ry == 0) ? 0 : p ->opta[1]); + Z1 = Z0 + ((rz == 0) ? 0 : p ->opta[0]); + + + // These are the 6 Tetrahedral + for (OutChan=0; OutChan < TotalOut; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) + { + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + } + else + if (rx >= rz && rz >= ry) + { + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + } + else + if (rz >= rx && rx >= ry) + { + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + } + else + if (ry >= rx && rx >= rz) + { + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + } + else + if (ry >= rz && rz >= rx) + { + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + } + else + if (rz >= ry && ry >= rx) + { + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + } + else { + c1 = c2 = c3 = 0; + } + + + Rest = c1 * rx + c2 * ry + c3 * rz; + + Output[OutChan] = (cmsUInt16Number)c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + + } +} + +#undef DENS + +// -------------------------------------------------------------------------------------------------------------- +// We need xput over here + +static +cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsPipeline* OriginalLut; + int nGridPoints; + cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS]; + cmsUInt32Number t, i; + cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS]; + cmsBool lIsSuitable, lIsLinear; + cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL; + cmsStage* OptimizedCLUTmpe; + cmsColorSpaceSignature ColorSpace, OutputColorSpace; + cmsStage* OptimizedPrelinMpe; + cmsToneCurve** OptimizedPrelinCurves; + _cmsStageCLutData* OptimizedPrelinCLUT; + + + // This is a loosy optimization! does not apply in floating-point cases + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; + + // Only on RGB + if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE; + if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE; + + + // On 16 bits, user has to specify the feature + if (!_cmsFormatterIs8bit(*InputFormat)) { + if (!(*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION)) return FALSE; + } + + OriginalLut = *Lut; + ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); + OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); + nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); + + // Empty gamma containers + memset(Trans, 0, sizeof(Trans)); + memset(TransReverse, 0, sizeof(TransReverse)); + + for (t = 0; t < OriginalLut ->InputChannels; t++) { + Trans[t] = cmsBuildTabulatedToneCurve16(OriginalLut ->ContextID, PRELINEARIZATION_POINTS, NULL); + if (Trans[t] == NULL) goto Error; + } + + // Populate the curves + for (i=0; i < PRELINEARIZATION_POINTS; i++) { + + v = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); + + // Feed input with a gray ramp + for (t=0; t < OriginalLut ->InputChannels; t++) + In[t] = v; + + // Evaluate the gray value + cmsPipelineEvalFloat(In, Out, OriginalLut); + + // Store result in curve + for (t=0; t < OriginalLut ->InputChannels; t++) + Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); + } + + // Slope-limit the obtained curves + for (t = 0; t < OriginalLut ->InputChannels; t++) + SlopeLimiting(Trans[t]); + + // Check for validity + lIsSuitable = TRUE; + lIsLinear = TRUE; + for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { + + // Exclude if already linear + if (!cmsIsToneCurveLinear(Trans[t])) + lIsLinear = FALSE; + + // Exclude if non-monotonic + if (!cmsIsToneCurveMonotonic(Trans[t])) + lIsSuitable = FALSE; + } + + // If it is not suitable, just quit + if (!lIsSuitable) goto Error; + + // Invert curves if possible + for (t = 0; t < OriginalLut ->InputChannels; t++) { + TransReverse[t] = cmsReverseToneCurveEx(PRELINEARIZATION_POINTS, Trans[t]); + if (TransReverse[t] == NULL) goto Error; + } + + // Now inset the reversed curves at the begin of transform + LutPlusCurves = cmsPipelineDup(OriginalLut); + if (LutPlusCurves == NULL) goto Error; + + cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse)); + + // Create the result LUT + OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); + if (OptimizedLUT == NULL) goto Error; + + OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); + + // Create and insert the curves at the beginning + cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe); + + // Allocate the CLUT for result + OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); + + // Add the CLUT to the destination LUT + cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe); + + // Resample the LUT + if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; + + // Free resources + for (t = 0; t < OriginalLut ->InputChannels; t++) { + + if (Trans[t]) cmsFreeToneCurve(Trans[t]); + if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); + } + + cmsPipelineFree(LutPlusCurves); + + + OptimizedPrelinCurves = _cmsStageGetPtrToCurveSet(OptimizedPrelinMpe); + OptimizedPrelinCLUT = (_cmsStageCLutData*) OptimizedCLUTmpe ->Data; + + // Set the evaluator if 8-bit + if (_cmsFormatterIs8bit(*InputFormat)) { + + Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID, + OptimizedPrelinCLUT ->Params, + OptimizedPrelinCurves); + if (p8 == NULL) return FALSE; + + _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup); + + } + else + { + Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID, + OptimizedPrelinCLUT ->Params, + 3, OptimizedPrelinCurves, 3, NULL); + if (p16 == NULL) return FALSE; + + _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); + + } + + // Don't fix white on absolute colorimetric + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; + + if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { + + if (!FixWhiteMisalignment(OptimizedLUT, ColorSpace, OutputColorSpace)) { + + return FALSE; + } + } + + // And return the obtained LUT + + cmsPipelineFree(OriginalLut); + *Lut = OptimizedLUT; + return TRUE; + +Error: + + for (t = 0; t < OriginalLut ->InputChannels; t++) { + + if (Trans[t]) cmsFreeToneCurve(Trans[t]); + if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); + } + + if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves); + if (OptimizedLUT != NULL) cmsPipelineFree(OptimizedLUT); + + return FALSE; + + cmsUNUSED_PARAMETER(Intent); +} + + +// Curves optimizer ------------------------------------------------------------------------------------------------------------------ + +static +void CurvesFree(cmsContext ContextID, void* ptr) +{ + Curves16Data* Data = (Curves16Data*) ptr; + int i; + + for (i=0; i < Data -> nCurves; i++) { + + _cmsFree(ContextID, Data ->Curves[i]); + } + + _cmsFree(ContextID, Data ->Curves); + _cmsFree(ContextID, ptr); +} + +static +void* CurvesDup(cmsContext ContextID, const void* ptr) +{ + Curves16Data* Data = _cmsDupMem(ContextID, ptr, sizeof(Curves16Data)); + int i; + + if (Data == NULL) return NULL; + + Data ->Curves = _cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*)); + + for (i=0; i < Data -> nCurves; i++) { + Data ->Curves[i] = _cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number)); + } + + return (void*) Data; +} + +// Precomputes tables for 8-bit on input devicelink. +static +Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G) +{ + int i, j; + Curves16Data* c16; + + c16 = _cmsMallocZero(ContextID, sizeof(Curves16Data)); + if (c16 == NULL) return NULL; + + c16 ->nCurves = nCurves; + c16 ->nElements = nElements; + + c16 ->Curves = _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*)); + if (c16 ->Curves == NULL) return NULL; + + for (i=0; i < nCurves; i++) { + + c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); + + if (nElements == 256) { + + for (j=0; j < nElements; j++) { + + c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j)); + } + } + else { + + for (j=0; j < nElements; j++) { + c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j); + } + } + } + + return c16; +} + +static +void FastEvaluateCurves8(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register const void* D) +{ + Curves16Data* Data = (Curves16Data*) D; + cmsUInt8Number x; + int i; + + for (i=0; i < Data ->nCurves; i++) { + + x = (In[i] >> 8); + Out[i] = Data -> Curves[i][x]; + } +} + + +static +void FastEvaluateCurves16(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register const void* D) +{ + Curves16Data* Data = (Curves16Data*) D; + int i; + + for (i=0; i < Data ->nCurves; i++) { + Out[i] = Data -> Curves[i][In[i]]; + } +} + + +static +void FastIdentity16(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register const void* D) +{ + cmsPipeline* Lut = (cmsPipeline*) D; + cmsUInt32Number i; + + for (i=0; i < Lut ->InputChannels; i++) { + Out[i] = In[i]; + } +} + + +// If the target LUT holds only curves, the optimization procedure is to join all those +// curves together. That only works on curves and does not work on matrices. +static +cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsToneCurve** GammaTables = NULL; + cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; + cmsUInt32Number i, j; + cmsPipeline* Src = *Lut; + cmsPipeline* Dest = NULL; + cmsStage* mpe; + cmsStage* ObtainedCurves = NULL; + + + // This is a loosy optimization! does not apply in floating-point cases + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; + + // Only curves in this LUT? + for (mpe = cmsPipelineGetPtrToFirstStage(Src); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE; + } + + // Allocate an empty LUT + Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); + if (Dest == NULL) return FALSE; + + // Create target curves + GammaTables = (cmsToneCurve**) _cmsCalloc(Src ->ContextID, Src ->InputChannels, sizeof(cmsToneCurve*)); + if (GammaTables == NULL) goto Error; + + for (i=0; i < Src ->InputChannels; i++) { + GammaTables[i] = cmsBuildTabulatedToneCurve16(Src ->ContextID, PRELINEARIZATION_POINTS, NULL); + if (GammaTables[i] == NULL) goto Error; + } + + // Compute 16 bit result by using floating point + for (i=0; i < PRELINEARIZATION_POINTS; i++) { + + for (j=0; j < Src ->InputChannels; j++) + InFloat[j] = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); + + cmsPipelineEvalFloat(InFloat, OutFloat, Src); + + for (j=0; j < Src ->InputChannels; j++) + GammaTables[j] -> Table16[i] = _cmsQuickSaturateWord(OutFloat[j] * 65535.0); + } + + ObtainedCurves = cmsStageAllocToneCurves(Src ->ContextID, Src ->InputChannels, GammaTables); + if (ObtainedCurves == NULL) goto Error; + + for (i=0; i < Src ->InputChannels; i++) { + cmsFreeToneCurve(GammaTables[i]); + GammaTables[i] = NULL; + } + + if (GammaTables != NULL) _cmsFree(Src ->ContextID, GammaTables); + + // Maybe the curves are linear at the end + if (!AllCurvesAreLinear(ObtainedCurves)) { + + cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves); + + // If the curves are to be applied in 8 bits, we can save memory + if (_cmsFormatterIs8bit(*InputFormat)) { + + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data; + Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); + + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); + + } + else { + + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); + Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); + + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); + } + } + else { + + // LUT optimizes to nothing. Set the identity LUT + cmsStageFree(ObtainedCurves); + + cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels)); + + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); + } + + // We are done. + cmsPipelineFree(Src); + *Lut = Dest; + return TRUE; + +Error: + + if (ObtainedCurves != NULL) cmsStageFree(ObtainedCurves); + if (GammaTables != NULL) { + for (i=0; i < Src ->InputChannels; i++) { + if (GammaTables[i] != NULL) cmsFreeToneCurve(GammaTables[i]); + } + + _cmsFree(Src ->ContextID, GammaTables); + } + + if (Dest != NULL) cmsPipelineFree(Dest); + return FALSE; + + cmsUNUSED_PARAMETER(Intent); + cmsUNUSED_PARAMETER(InputFormat); + cmsUNUSED_PARAMETER(OutputFormat); + cmsUNUSED_PARAMETER(dwFlags); +} + +// ------------------------------------------------------------------------------------------------------------------------------------- +// LUT is Shaper - Matrix - Matrix - Shaper, which is very frequent when combining two matrix-shaper profiles + + +static +void FreeMatShaper(cmsContext ContextID, void* Data) +{ + if (Data != NULL) _cmsFree(ContextID, Data); +} + +static +void* DupMatShaper(cmsContext ContextID, const void* Data) +{ + return _cmsDupMem(ContextID, Data, sizeof(MatShaper8Data)); +} + + +// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point +// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits, +// in total about 50K, and the performance boost is huge! +static +void MatShaperEval16(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register const void* D) +{ + MatShaper8Data* p = (MatShaper8Data*) D; + cmsS1Fixed14Number l1, l2, l3, r, g, b; + cmsUInt32Number ri, gi, bi; + + // In this case (and only in this case!) we can use this simplification since + // In[] is assured to come from a 8 bit number. (a << 8 | a) + ri = In[0] & 0xFF; + gi = In[1] & 0xFF; + bi = In[2] & 0xFF; + + // Across first shaper, which also converts to 1.14 fixed point + r = p->Shaper1R[ri]; + g = p->Shaper1G[gi]; + b = p->Shaper1B[bi]; + + // Evaluate the matrix in 1.14 fixed point + l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14; + l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14; + l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14; + + // Now we have to clip to 0..1.0 range + ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1); + gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2); + bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3); + + // And across second shaper, + Out[0] = p->Shaper2R[ri]; + Out[1] = p->Shaper2G[gi]; + Out[2] = p->Shaper2B[bi]; + +} + +// This table converts from 8 bits to 1.14 after applying the curve +static +void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) +{ + int i; + cmsFloat32Number R, y; + + for (i=0; i < 256; i++) { + + R = (cmsFloat32Number) (i / 255.0); + y = cmsEvalToneCurveFloat(Curve, R); + + Table[i] = DOUBLE_TO_1FIXED14(y); + } +} + +// This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve +static +void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) +{ + int i; + cmsFloat32Number R, Val; + + for (i=0; i < 16385; i++) { + + R = (cmsFloat32Number) (i / 16384.0); + Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 + + if (Is8BitsOutput) { + + // If 8 bits output, we can optimize further by computing the / 257 part. + // first we compute the resulting byte and then we store the byte times + // 257. This quantization allows to round very quick by doing a >> 8, but + // since the low byte is always equal to msb, we can do a & 0xff and this works! + cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0 + 0.5); + cmsUInt8Number b = FROM_16_TO_8(w); + + Table[i] = FROM_8_TO_16(b); + } + else Table[i] = _cmsQuickSaturateWord(Val * 65535.0 + 0.5); + } +} + +// Compute the matrix-shaper structure +static +cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, cmsVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat) +{ + MatShaper8Data* p; + int i, j; + cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat); + + // Allocate a big chuck of memory to store precomputed tables + p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data)); + if (p == NULL) return FALSE; + + p -> ContextID = Dest -> ContextID; + + // Precompute tables + FillFirstShaper(p ->Shaper1R, Curve1[0]); + FillFirstShaper(p ->Shaper1G, Curve1[1]); + FillFirstShaper(p ->Shaper1B, Curve1[2]); + + FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits); + FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits); + FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits); + + // Convert matrix to nFixed14. Note that those values may take more than 16 bits as + for (i=0; i < 3; i++) { + for (j=0; j < 3; j++) { + p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); + } + } + + for (i=0; i < 3; i++) { + + if (Off == NULL) { + p ->Off[i] = 0; + } + else { + p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); + } + } + + // Mark as optimized for faster formatter + if (Is8Bits) + *OutputFormat |= OPTIMIZED_SH(1); + + // Fill function pointers + _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); + return TRUE; +} + +// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! +// TODO: Allow a third matrix for abs. colorimetric +static +cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsStage* Curve1, *Curve2; + cmsStage* Matrix1, *Matrix2; + _cmsStageMatrixData* Data1; + _cmsStageMatrixData* Data2; + cmsMAT3 res; + cmsBool IdentityMat; + cmsPipeline* Dest, *Src; + + // Only works on RGB to RGB + if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; + + // Only works on 8 bit input + if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE; + + // Seems suitable, proceed + Src = *Lut; + + // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for + if (!cmsPipelineCheckAndRetreiveStages(Src, 4, + cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE; + + // Get both matrices + Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1); + Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2); + + // Input offset should be zero + if (Data1 ->Offset != NULL) return FALSE; + + // Multiply both matrices to get the result + _cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double); + + // Now the result is in res + Data2 -> Offset. Maybe is a plain identity? + IdentityMat = FALSE; + if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) { + + // We can get rid of full matrix + IdentityMat = TRUE; + } + + // Allocate an empty LUT + Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); + if (!Dest) return FALSE; + + // Assamble the new LUT + cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)); + if (!IdentityMat) + cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset)); + cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)); + + // If identity on matrix, we can further optimize the curves, so call the join curves routine + if (IdentityMat) { + + OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags); + } + else { + _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); + _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); + + // In this particular optimization, caché does not help as it takes more time to deal with + // the caché that with the pixel handling + *dwFlags |= cmsFLAGS_NOCACHE; + + // Setup the optimizarion routines + SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat); + } + + cmsPipelineFree(Src); + *Lut = Dest; + return TRUE; +} + + +// ------------------------------------------------------------------------------------------------------------------------------------- +// Optimization plug-ins + +// List of optimizations +typedef struct _cmsOptimizationCollection_st { + + _cmsOPToptimizeFn OptimizePtr; + + struct _cmsOptimizationCollection_st *Next; + +} _cmsOptimizationCollection; + + +// The built-in list. We currently implement 4 types of optimizations. Joining of curves, matrix-shaper, linearization and resampling +static _cmsOptimizationCollection DefaultOptimization[] = { + + { OptimizeByJoiningCurves, &DefaultOptimization[1] }, + { OptimizeMatrixShaper, &DefaultOptimization[2] }, + { OptimizeByComputingLinearization, &DefaultOptimization[3] }, + { OptimizeByResampling, NULL } +}; + +// The linked list head +static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; + +// Register new ways to optimize +cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data) +{ + cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; + _cmsOptimizationCollection* fl; + + if (Data == NULL) { + + OptimizationCollection = DefaultOptimization; + return TRUE; + } + + // Optimizer callback is required + if (Plugin ->OptimizePtr == NULL) return FALSE; + + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(sizeof(_cmsOptimizationCollection)); + if (fl == NULL) return FALSE; + + // Copy the parameters + fl ->OptimizePtr = Plugin ->OptimizePtr; + + // Keep linked list + fl ->Next = OptimizationCollection; + OptimizationCollection = fl; + + // All is ok + return TRUE; +} + +// The entry point for LUT optimization +cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, + int Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags) +{ + _cmsOptimizationCollection* Opts; + cmsBool AnySuccess = FALSE; + + // A CLUT is being asked, so force this specific optimization + if (*dwFlags & cmsFLAGS_FORCE_CLUT) { + + PreOptimize(*PtrLut); + return OptimizeByResampling(PtrLut, Intent, InputFormat, OutputFormat, dwFlags); + } + + // Anything to optimize? + if ((*PtrLut) ->Elements == NULL) { + _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); + return TRUE; + } + + // Try to get rid of identities and trivial conversions. + AnySuccess = PreOptimize(*PtrLut); + + // After removal do we end with an identity? + if ((*PtrLut) ->Elements == NULL) { + _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); + return TRUE; + } + + // Do not optimize, keep all precision + if (*dwFlags & cmsFLAGS_NOOPTIMIZE) + return FALSE; + + // Try built-in optimizations and plug-in + for (Opts = OptimizationCollection; + Opts != NULL; + Opts = Opts ->Next) { + + // If one schema succeeded, we are done + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; // Optimized! + } + } + + // Only simple optimizations succeeded + return AnySuccess; +} + + + diff --git a/thirdparty/liblcms2/src/cmspack.c b/thirdparty/liblcms2/src/cmspack.c new file mode 100644 index 00000000..196afa94 --- /dev/null +++ b/thirdparty/liblcms2/src/cmspack.c @@ -0,0 +1,2558 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// This module handles all formats supported by lcms. There are two flavors, 16 bits and +// floating point. Floating point is supported only in a subset, those formats holding +// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component as special +// case) + +// --------------------------------------------------------------------------- + + +// This macro return words stored as big endian +#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8)) + +// These macros handles reversing (negative) +#define REVERSE_FLAVOR_8(x) ((cmsUInt8Number) (0xff-(x))) +#define REVERSE_FLAVOR_16(x) ((cmsUInt16Number)(0xffff-(x))) + +// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256 +cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) +{ + int a; + + a = (x << 8 | x) >> 8; // * 257 / 256 + if ( a > 0xffff) return 0xffff; + return (cmsUInt16Number) a; +} + +// * 0xf00 / 0xffff = * 256 / 257 +cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) +{ + return (cmsUInt16Number) (((x << 8) + 0x80) / 257); +} + + +typedef struct { + cmsUInt32Number Type; + cmsUInt32Number Mask; + cmsFormatter16 Frm; + +} cmsFormatters16; + +typedef struct { + cmsUInt32Number Type; + cmsUInt32Number Mask; + cmsFormatterFloat Frm; + +} cmsFormattersFloat; + +#define ANYSPACE COLORSPACE_SH(31) +#define ANYCHANNELS CHANNELS_SH(15) +#define ANYEXTRA EXTRA_SH(7) +#define ANYPLANAR PLANAR_SH(1) +#define ANYENDIAN ENDIAN16_SH(1) +#define ANYSWAP DOSWAP_SH(1) +#define ANYSWAPFIRST SWAPFIRST_SH(1) +#define ANYFLAVOR FLAVOR_SH(1) + + +// Supress waning about info never being used + +#ifdef _MSC_VER +#pragma warning(disable : 4100) +#endif + +// Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- + +// Does almost everything but is slow +static +cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap && !SwapFirst; + cmsUInt16Number v; + int i; + + if (ExtraFirst) { + accum += Extra; + } + + for (i=0; i < nChan; i++) { + int index = DoSwap ? (nChan - i - 1) : i; + + v = FROM_8_TO_16(*accum); + v = Reverse ? REVERSE_FLAVOR_16(v) : v; + wIn[index] = v; + accum++; + } + + if (!ExtraFirst) { + accum += Extra; + } + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + return accum; +} + +// Extra channels are just ignored because come in the next planes +static +cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap= T_DOSWAP(info ->InputFormat); + int Reverse= T_FLAVOR(info ->InputFormat); + int i; + cmsUInt8Number* Init = accum; + + if (DoSwap) { + accum += T_EXTRA(info -> InputFormat) * Stride; + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + cmsUInt16Number v = FROM_8_TO_16(*accum); + + wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + accum += Stride; + } + + return (Init + 1); +} + +// Special cases, provided for performance +static +cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(*accum); accum++; // C + wIn[1] = FROM_8_TO_16(*accum); accum++; // M + wIn[2] = FROM_8_TO_16(*accum); accum++; // Y + wIn[3] = FROM_8_TO_16(*accum); accum++; // K + + return accum; +} + +static +cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C + wIn[1] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M + wIn[2] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y + wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K + + return accum; +} + +static +cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[3] = FROM_8_TO_16(*accum); accum++; // K + wIn[0] = FROM_8_TO_16(*accum); accum++; // C + wIn[1] = FROM_8_TO_16(*accum); accum++; // M + wIn[2] = FROM_8_TO_16(*accum); accum++; // Y + + return accum; +} + +// KYMC +static +cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[3] = FROM_8_TO_16(*accum); accum++; // K + wIn[2] = FROM_8_TO_16(*accum); accum++; // Y + wIn[1] = FROM_8_TO_16(*accum); accum++; // M + wIn[0] = FROM_8_TO_16(*accum); accum++; // C + + return accum; +} + +static +cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // K + wIn[1] = FROM_8_TO_16(*accum); accum++; // Y + wIn[0] = FROM_8_TO_16(*accum); accum++; // M + wIn[3] = FROM_8_TO_16(*accum); accum++; // C + + return accum; +} + +static +cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + + return accum; +} + +static +cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + accum++; // A + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + + return accum; +} + +static +cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + accum++; // A + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + + return accum; +} + + +// BRG +static +cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + + return accum; +} + +static +cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L + wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a + wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b + + return accum; +} + +static +cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + accum++; // A + wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L + wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a + wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b + + return accum; +} + +static +cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L + wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a + wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b + + return accum; +} + +// for duplex +static +cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(*accum); accum++; // ch1 + wIn[1] = FROM_8_TO_16(*accum); accum++; // ch2 + return accum; +} + + + + +// Monochrome duplicates L into RGB for null-transforms +static +cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + return accum; +} + + +static +cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + accum += 1; + return accum; +} + +static +cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + accum += 2; + return accum; +} + +static +cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++; // L + return accum; +} + + +static +cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> InputFormat); + int SwapEndian = T_ENDIAN16(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap && !SwapFirst; + int i; + + if (ExtraFirst) { + accum += Extra * sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + cmsUInt16Number v = *(cmsUInt16Number*) accum; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + + accum += sizeof(cmsUInt16Number); + } + + if (!ExtraFirst) { + accum += Extra * sizeof(cmsUInt16Number); + } + + if (Extra == 0 && SwapFirst) { + + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + return accum; +} + +static +cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap= T_DOSWAP(info ->InputFormat); + int Reverse= T_FLAVOR(info ->InputFormat); + int SwapEndian = T_ENDIAN16(info -> InputFormat); + int i; + cmsUInt8Number* Init = accum; + + if (DoSwap) { + accum += T_EXTRA(info -> InputFormat) * Stride * sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + cmsUInt16Number v = *(cmsUInt16Number*) accum; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + + accum += Stride * sizeof(cmsUInt16Number); + } + + return (Init + sizeof(cmsUInt16Number)); +} + + +static +cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K + + return accum; +} + +static +cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C + wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M + wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y + wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K + + return accum; +} + +static +cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y + + return accum; +} + +// KYMC +static +cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C + + return accum; +} + +static +cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C + + return accum; +} + +static +cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C R + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y B + return accum; +} + +static +cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // C R + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // Y B + return accum; +} + +static +cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + accum += 2; // A + wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R + wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G + wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B + + return accum; +} + +static +cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + accum += 2; // A + wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R + wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G + wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B + + return accum; +} + +static +cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L + return accum; +} + +static +cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; + return accum; +} + +static +cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; + + accum += 8; + return accum; +} + +static +cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // ch1 + wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // ch2 + + return accum; +} + + +// This is a conversion of Lab double to 16 bits +static +cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat64Number* Pt = (cmsFloat64Number*) accum; + + cmsCIELab Lab; + + Lab.L = Pt[0]; + Lab.a = Pt[Stride]; + Lab.b = Pt[Stride*2]; + + cmsFloat2LabEncoded(wIn, &Lab); + return accum + sizeof(cmsFloat64Number); + } + else { + + cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum); + accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); + return accum; + } +} + +// This is a conversion of XYZ double to 16 bits +static +cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat64Number* Pt = (cmsFloat64Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[Stride]; + XYZ.Z = Pt[Stride*2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + return accum + sizeof(cmsFloat64Number); + + } + + else { + cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum); + accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); + + return accum; + } +} + +// Check if space is marked as ink +cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) +{ + switch (T_COLORSPACE(Type)) { + + case PT_CMY: + case PT_CMYK: + case PT_MCH5: + case PT_MCH6: + case PT_MCH7: + case PT_MCH8: + case PT_MCH9: + case PT_MCH10: + case PT_MCH11: + case PT_MCH12: + case PT_MCH13: + case PT_MCH14: + case PT_MCH15: return TRUE; + + default: return FALSE; + } +} + +// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits +static +cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + cmsFloat64Number* Inks = (cmsFloat64Number*) accum; + int nChan = T_CHANNELS(info -> InputFormat); + int Planar = T_PLANAR(info -> InputFormat); + int i; + cmsFloat64Number v; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + for (i=0; i < nChan; i++) { + + if (Planar) + + v = Inks[i * Stride]; + else + v = Inks[i]; + + wIn[i] = _cmsQuickSaturateWord(v * maximum); + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat64Number); + else + return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number); +} + +static +cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + cmsFloat32Number* Inks = (cmsFloat32Number*) accum; + int nChan = T_CHANNELS(info -> InputFormat); + int Planar = T_PLANAR(info -> InputFormat); + int i; + cmsFloat32Number v; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + for (i=0; i < nChan; i++) { + + if (Planar) + + v = Inks[i * Stride]; + else + v = Inks[i]; + + wIn[i] = _cmsQuickSaturateWord(v * maximum); + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat32Number); + else + return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); +} + + +// For 1 channel, we need to duplicate data (it comes in 0..1.0 range) +static +cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + cmsFloat64Number* Inks = (cmsFloat64Number*) accum; + + wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0); + + return accum + sizeof(cmsFloat64Number); +} + +//------------------------------------------------------------------------------------------------------------------- + +// True float transformation. + +// For anything going from cmsFloat32Number +static +cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Inks = (cmsFloat32Number*) accum; + int nChan = T_CHANNELS(info -> InputFormat); + int Planar = T_PLANAR(info -> InputFormat); + int i; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; + + + for (i=0; i < nChan; i++) { + + if (Planar) + wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum); + else + wIn[i] = (cmsFloat32Number) (Inks[i] / maximum); + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat32Number); + else + return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); +} + +// For anything going from double +static +cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Inks = (cmsFloat64Number*) accum; + int nChan = T_CHANNELS(info -> InputFormat); + int Planar = T_PLANAR(info -> InputFormat); + int i; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; + + for (i=0; i < nChan; i++) { + + if (Planar) + wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum); + else + wIn[i] = (cmsFloat32Number) (Inks[i] / maximum); + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat64Number); + else + return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number); +} + + +// From Lab double to cmsFloat32Number +static +cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Pt = (cmsFloat64Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); + + return accum + sizeof(cmsFloat64Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); + + accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + +// From Lab double to cmsFloat32Number +static +cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); + + return accum + sizeof(cmsFloat32Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); + + accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + + +// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF) +static +cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Pt = (cmsFloat64Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); + + return accum + sizeof(cmsFloat64Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); + + accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + +static +cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); + + return accum + sizeof(cmsFloat32Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); + + accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + +// Packing routines ----------------------------------------------------------------------------------------------------------- + + +// Generic chunky for byte + +static +cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int ExtraFirst = DoSwap && !SwapFirst; + cmsUInt8Number* swap1; + cmsUInt8Number v = 0; + int i; + + swap1 = output; + + if (ExtraFirst) { + output += Extra; + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = FROM_16_TO_8(wOut[index]); + + if (Reverse) + v = REVERSE_FLAVOR_8(v); + + *output++ = v; + } + + if (!ExtraFirst) { + output += Extra; + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, nChan-1); + *swap1 = v; + } + + + return output; +} + + + +static +cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int SwapEndian = T_ENDIAN16(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int ExtraFirst = DoSwap && !SwapFirst; + cmsUInt16Number* swap1; + cmsUInt16Number v = 0; + int i; + + swap1 = (cmsUInt16Number*) output; + + if (ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index]; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + if (Reverse) + v = REVERSE_FLAVOR_16(v); + + *(cmsUInt16Number*) output = v; + + output += sizeof(cmsUInt16Number); + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); + *swap1 = v; + } + + + return output; +} + + +static +cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse= T_FLAVOR(info ->OutputFormat); + int i; + cmsUInt8Number* Init = output; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + cmsUInt8Number v = FROM_16_TO_8(wOut[index]); + + *(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v); + output += Stride; + } + + return (Init + 1); +} + + +static +cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse= T_FLAVOR(info ->OutputFormat); + int SwapEndian = T_ENDIAN16(info -> OutputFormat); + int i; + cmsUInt8Number* Init = output; + cmsUInt16Number v; + + if (DoSwap) { + output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index]; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + if (Reverse) + v = REVERSE_FLAVOR_16(v); + + *(cmsUInt16Number*) output = v; + output += (Stride * sizeof(cmsUInt16Number)); + } + + return (Init + sizeof(cmsUInt16Number)); +} + +// CMYKcm (unrolled for speed) + +static +cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[4]); + *output++ = FROM_16_TO_8(wOut[5]); + + return output; +} + +// KCMYcm + +static +cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[5]); + *output++ = FROM_16_TO_8(wOut[4]); + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; +} + +// CMYKcm +static +cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + *(cmsUInt16Number*) output = wOut[4]; + output+= 2; + *(cmsUInt16Number*) output = wOut[5]; + output+= 2; + + return output; +} + +// KCMYcm +static +cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[5]; + output+= 2; + *(cmsUInt16Number*) output = wOut[4]; + output+= 2; + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; +} + + +static +cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[3]); + + return output; +} + +static +cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0])); + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1])); + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2])); + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3])); + + return output; +} + + +static +cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + + return output; +} + +// ABGR +static +cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; +} + +static +cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[3]); + + return output; +} + +static +cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + + return output; +} + +static +cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]); + output+= 2; + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]); + output+= 2; + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]); + output+= 2; + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]); + output+= 2; + + return output; +} + +// ABGR +static +cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; +} + +// CMYK +static +cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]); + output+= 2; + + return output; +} + + +static +cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); + + return output; +} + +static +cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); + + return output; +} + +static +cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]); + output += 2; + *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]); + output += 2; + *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]); + output += 2; + + return output; +} + +static +cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + + return output; +} + +static +cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = (wOut[0] & 0xFF); + *output++ = (wOut[1] & 0xFF); + *output++ = (wOut[2] & 0xFF); + + return output; +} + +static +cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; +} + +static +cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = (wOut[2] & 0xFF); + *output++ = (wOut[1] & 0xFF); + *output++ = (wOut[0] & 0xFF); + + return output; +} + + +static +cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + + return output; +} + +static +cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; +} + +static +cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]); + output+= 2; + + return output; +} + +static +cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + output++; + + return output; +} + +static +cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = (wOut[0] & 0xFF); + *output++ = (wOut[1] & 0xFF); + *output++ = (wOut[2] & 0xFF); + output++; + + return output; +} + + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + + return output; +} + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output++; + *output++ = (wOut[0] & 0xFF); + *output++ = (wOut[1] & 0xFF); + *output++ = (wOut[2] & 0xFF); + + return output; +} + +static +cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; +} + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output++; + *output++ = (wOut[2] & 0xFF); + *output++ = (wOut[1] & 0xFF); + *output++ = (wOut[0] & 0xFF); + + return output; +} + + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + output++; + + return output; +} + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = (wOut[2] & 0xFF); + *output++ = (wOut[1] & 0xFF); + *output++ = (wOut[0] & 0xFF); + output++; + + return output; +} + +static +cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + output+= 2; + + return output; +} + +static +cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; +} + + +static +cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + + return output; +} + + +static +cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + output+= 2; + + return output; +} + + + +static +cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + return output; +} + + +static +cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0])); + return output; +} + + +static +cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + output++; + return output; +} + + +static +cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(wOut[0]); + + return output; +} + +static +cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; +} + + +static +cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]); + output+= 2; + + return output; +} + +static +cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); + output+= 2; + + return output; +} + + +static +cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 4; + + return output; +} + +static +cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + output += 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; +} + + +// Unencoded Float values -- don't try optimize speed +static +cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + + if (T_PLANAR(Info -> OutputFormat)) { + + cmsCIELab Lab; + cmsFloat64Number* Out = (cmsFloat64Number*) output; + cmsLabEncoded2Float(&Lab, wOut); + + Out[0] = Lab.L; + Out[Stride] = Lab.a; + Out[Stride*2] = Lab.b; + + return output + sizeof(cmsFloat64Number); + } + else { + + cmsLabEncoded2Float((cmsCIELab*) output, wOut); + return output + (sizeof(cmsCIELab) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } + +} + +static +cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(Info -> OutputFormat)) { + + cmsCIEXYZ XYZ; + cmsFloat64Number* Out = (cmsFloat64Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Out[0] = XYZ.X; + Out[Stride] = XYZ.Y; + Out[Stride*2] = XYZ.Z; + + return output + sizeof(cmsFloat64Number); + + } + else { + + cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut); + + return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } +} + +static +cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + cmsFloat64Number* Inks = (cmsFloat64Number*) output; + int nChan = T_CHANNELS(Info -> OutputFormat); + int i; + cmsFloat64Number maximum = IsInkSpace(Info ->InputFormat) ? 655.35 : 65535.0; + + if (T_PLANAR(Info -> OutputFormat)) { + + for (i=0; i < nChan; i++) { + + Inks[i*Stride] = wOut[i] / maximum; + } + + return output + sizeof(cmsFloat64Number); + } + else { + + for (i=0; i < nChan; i++) { + + Inks[i] = wOut[i] / maximum; + } + + + return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat64Number); + } + +} + +static +cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + cmsFloat32Number* Inks = (cmsFloat32Number*) output; + int nChan = T_CHANNELS(Info -> OutputFormat); + int i; + cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0; + + if (T_PLANAR(Info -> OutputFormat)) { + + for (i=0; i < nChan; i++) { + + Inks[i*Stride] = (cmsFloat32Number) (wOut[i] / maximum); + } + + return output + sizeof(cmsFloat32Number); + } + else { + + for (i=0; i < nChan; i++) { + + Inks[i] = (cmsFloat32Number) (wOut[i] / maximum); + } + + + return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat32Number); + } + +} + + +// -------------------------------------------------------------------------------------------------------- + +static +cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int ExtraFirst = DoSwap && !SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; + cmsFloat32Number* swap1; + cmsFloat64Number v = 0; + int i; + + swap1 = (cmsFloat32Number*) output; + + if (ExtraFirst) { + output += Extra * sizeof(cmsFloat32Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + *(cmsFloat32Number*) output = (cmsFloat32Number) v; + + output += sizeof(cmsFloat32Number); + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsFloat32Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); + *swap1 = (cmsFloat32Number) v; + } + + + return output; +} + +static +cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse= T_FLAVOR(info ->OutputFormat); + int i; + cmsUInt8Number* Init = output; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; + cmsFloat64Number v; + + if (DoSwap) { + output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat32Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + *(cmsFloat32Number*) output = (cmsFloat32Number) v; + output += (Stride * sizeof(cmsFloat32Number)); + } + + return (Init + sizeof(cmsFloat32Number)); +} + + +static +cmsUInt8Number* PackChunkyDoublesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int ExtraFirst = DoSwap && !SwapFirst; + cmsFloat64Number* swap1; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; + cmsFloat64Number v = 0; + int i; + + swap1 = (cmsFloat64Number*) output; + + if (ExtraFirst) { + output += Extra * sizeof(cmsFloat64Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat64Number) wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + *(cmsFloat64Number*) output = v; + + output += sizeof(cmsFloat64Number); + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsFloat64Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); + *swap1 = v; + } + + + return output; +} + +static +cmsUInt8Number* PackPlanarDoublesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse= T_FLAVOR(info ->OutputFormat); + int i; + cmsUInt8Number* Init = output; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; + cmsFloat64Number v; + + if (DoSwap) { + output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat64Number); + } + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat64Number) wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + *(cmsFloat64Number*) output = v; + output += (Stride * sizeof(cmsFloat64Number)); + } + + return (Init + sizeof(cmsFloat64Number)); +} + + + + +static +cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); + Out[Stride] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); + Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); + + return output + sizeof(cmsFloat32Number); + } + else { + + Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); + Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); + Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); + + return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } + +} + +static +cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Out = (cmsFloat64Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); + Out[Stride] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); + Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); + + return output + sizeof(cmsFloat64Number); + } + else { + + Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); + Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); + Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); + + return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } + +} + + +// From 0..1 range to 0..MAX_ENCODEABLE_XYZ +static +cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[Stride] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + sizeof(cmsFloat32Number); + } + else { + + Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } + +} + + +// Same, but convert to double +static +cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Out = (cmsFloat64Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[Stride] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + sizeof(cmsFloat64Number); + } + else { + + Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } + +} + + +// ---------------------------------------------------------------------------------------------------------------- + + +static cmsFormatters16 InputFormatters16[] = { + + // Type Mask Function + // ---------------------------- ------------------------------------ ---------------------------- + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, + { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, + { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, + { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollFloatTo16}, + + + { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Unroll1Byte}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Unroll1ByteSkip1}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2), ANYSPACE, Unroll1ByteSkip2}, + { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll1ByteReversed}, + { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1), 0, Unroll2Bytes}, + + { TYPE_LabV2_8, 0, UnrollLabV2_8 }, + { TYPE_ALabV2_8, 0, UnrollALabV2_8 }, + { TYPE_LabV2_16, 0, UnrollLabV2_16 }, + + { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Unroll3Bytes}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSwap}, + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap}, + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst}, + + { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes}, + { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse}, + { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst}, + + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, + + + { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word}, + { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed}, + { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3), ANYSPACE, Unroll1WordSkip3}, + + { CHANNELS_SH(2)|BYTES_SH(2), ANYSPACE, Unroll2Words}, + { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Unroll3Words}, + { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Unroll4Words}, + + { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSwap}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3WordsSkip1SwapFirst}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSkip1Swap}, + { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll4WordsReverse}, + { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll4WordsSwap}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst}, + + + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords }, + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, +}; + + + +static cmsFormattersFloat InputFormattersFloat[] = { + + // Type Mask Function + // ---------------------------- ------------------------------------ ---------------------------- + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleToFloat}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatToFloat}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleToFloat}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat}, + + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, + { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, +}; + + +// Bit fields set to one in the mask are not compared +static +cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsFormatter fr; + + + if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) { + + for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) { + cmsFormatters16* f = InputFormatters16 + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.Fmt16 = f ->Frm; + return fr; + } + } + } + else { + for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { + cmsFormattersFloat* f = InputFormattersFloat + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.FmtFloat = f ->Frm; + return fr; + } + } + } + + fr.Fmt16 = NULL; + return fr; +} + +static cmsFormatters16 OutputFormatters16[] = { + // Type Mask Function + // ---------------------------- ------------------------------------ ---------------------------- + + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFrom16}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, + { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, + { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16}, + + { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Pack1Byte}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack1ByteSkip1}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1ByteSkip1SwapFirst}, + + { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack1ByteReversed}, + + { TYPE_LabV2_8, 0, PackLabV2_8 }, + { TYPE_ALabV2_8, 0, PackALabV2_8 }, + { TYPE_LabV2_16, 0, PackLabV2_16 }, + + { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1Optimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapFirstOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapSwapFirstOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesSwapOptimized}, + + + + { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Pack3Bytes}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapFirst}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap}, + { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes}, + { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes}, + { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse}, + { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst}, + + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes}, + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, + + { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word}, + { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1}, + { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1WordSkip1SwapFirst}, + { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack1WordReversed}, + { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack1WordBigEndian}, + { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Pack3Words}, + { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack3WordsSwap}, + { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack3WordsBigEndian}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack3WordsAndSkip1}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3WordsAndSkip1Swap}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3WordsAndSkip1SwapFirst}, + + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Pack3WordsAndSkip1SwapSwapFirst}, + + { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Pack4Words}, + { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack4WordsReverse}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack4WordsSwap}, + { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack4WordsBigEndian}, + + { CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words}, + { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap}, + + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords} + +}; + + +static cmsFormattersFloat OutputFormattersFloat[] = { + // Type Mask Function + // ---------------------------- --------------------------------------------------- ---------------------------- + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFromFloat}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFromFloat}, + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, + { FLOAT_SH(1)|BYTES_SH(4), + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyFloatsFromFloat }, + { FLOAT_SH(1)|BYTES_SH(4)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarFloatsFromFloat}, + { FLOAT_SH(1)|BYTES_SH(0), + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyDoublesFromFloat }, + { FLOAT_SH(1)|BYTES_SH(0)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarDoublesFromFloat}, + + +}; + + +// Bit fields set to one in the mask are not compared +cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsFormatter fr; + + + if (dwFlags & CMS_PACK_FLAGS_FLOAT) { + + for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { + cmsFormattersFloat* f = OutputFormattersFloat + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.FmtFloat = f ->Frm; + return fr; + } + } + + } + else { + + for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) { + cmsFormatters16* f = OutputFormatters16 + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.Fmt16 = f ->Frm; + return fr; + } + } + } + + fr.Fmt16 = NULL; + return fr; +} + + +typedef struct _cms_formatters_factory_list { + + cmsFormatterFactory Factory; + struct _cms_formatters_factory_list *Next; + +} cmsFormattersFactoryList; + +static cmsFormattersFactoryList* FactoryList = NULL; + + +// Formatters management +cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) +{ + cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; + cmsFormattersFactoryList* fl ; + + // Reset + if (Data == NULL) { + + FactoryList = NULL; + return TRUE; + } + + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList)); + if (fl == NULL) return FALSE; + + fl ->Factory = Plugin ->FormattersFactory; + + fl ->Next = FactoryList; + FactoryList = fl; + + return TRUE; +} + +cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags) // Float or 16 bits +{ + cmsFormattersFactoryList* f; + + for (f = FactoryList; f != NULL; f = f ->Next) { + + cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); + if (fn.Fmt16 != NULL) return fn; + } + + // Revert to default + if (Dir == cmsFormatterInput) + return _cmsGetStockInputFormatter(Type, dwFlags); + else + return _cmsGetStockOutputFormatter(Type, dwFlags); +} + + +// Return whatever given formatter refers to float values +cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type) +{ + return T_FLOAT(Type) ? TRUE : FALSE; +} + +// Return whatever given formatter refers to 8 bits +cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type) +{ + int Bytes = T_BYTES(Type); + + return (Bytes == 1); +} + +// Build a suitable formatter for the colorspace of this profile +cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) +{ + + cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile); + cmsUInt32Number ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace); + cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); + cmsUInt32Number Float = lIsFloat ? 1 : 0; + + // Create a fake formatter for result + return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); +} + +// Build a suitable formatter for the colorspace of this profile +cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) +{ + + cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); + int ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace); + cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); + cmsUInt32Number Float = lIsFloat ? 1 : 0; + + // Create a fake formatter for result + return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); +} + diff --git a/thirdparty/liblcms2/src/cmspcs.c b/thirdparty/liblcms2/src/cmspcs.c new file mode 100644 index 00000000..8dd1c22c --- /dev/null +++ b/thirdparty/liblcms2/src/cmspcs.c @@ -0,0 +1,926 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// inter PCS conversions XYZ <-> CIE L* a* b* +/* + + + CIE 15:2004 CIELab is defined as: + + L* = 116*f(Y/Yn) - 16 0 <= L* <= 100 + a* = 500*[f(X/Xn) - f(Y/Yn)] + b* = 200*[f(Y/Yn) - f(Z/Zn)] + + and + + f(t) = t^(1/3) 1 >= t > (24/116)^3 + (841/108)*t + (16/116) 0 <= t <= (24/116)^3 + + + Reverse transform is: + + X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116) + = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116) + + + + PCS in Lab2 is encoded as: + + 8 bit Lab PCS: + + L* 0..100 into a 0..ff byte. + a* t + 128 range is -128.0 +127.0 + b* + + 16 bit Lab PCS: + + L* 0..100 into a 0..ff00 word. + a* t + 128 range is -128.0 +127.9961 + b* + + + +Interchange Space Component Actual Range Encoded Range +CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff +CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff +CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff + +Version 2,3 +----------- + +CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00 +CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff +CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff + + +Version 4 +--------- + +CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff +CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff +CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff + +*/ + +// Conversions +void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source) +{ + cmsFloat64Number ISum; + + ISum = 1./(Source -> X + Source -> Y + Source -> Z); + + Dest -> x = (Source -> X) * ISum; + Dest -> y = (Source -> Y) * ISum; + Dest -> Y = Source -> Y; +} + +void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source) +{ + Dest -> X = (Source -> x / Source -> y) * Source -> Y; + Dest -> Y = Source -> Y; + Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y; +} + +static +cmsFloat64Number f(cmsFloat64Number t) +{ + const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0); + + if (t <= Limit) + return (841.0/108.0) * t + (16.0/116.0); + else + return pow(t, 1.0/3.0); +} + +static +cmsFloat64Number f_1(cmsFloat64Number t) +{ + const cmsFloat64Number Limit = (24.0/116.0); + + if (t <= Limit) { + return (108.0/841.0) * (t - (16.0/116.0)); + } + + return t * t * t; +} + + +// Standard XYZ to Lab. it can handle negative XZY numbers in some cases +void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz) +{ + cmsFloat64Number fx, fy, fz; + + if (WhitePoint == NULL) + WhitePoint = cmsD50_XYZ(); + + fx = f(xyz->X / WhitePoint->X); + fy = f(xyz->Y / WhitePoint->Y); + fz = f(xyz->Z / WhitePoint->Z); + + Lab->L = 116.0*fy - 16.0; + Lab->a = 500.0*(fx - fy); + Lab->b = 200.0*(fy - fz); +} + + +// Standard XYZ to Lab. It can return negative XYZ in some cases +void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab) +{ + cmsFloat64Number x, y, z; + + if (WhitePoint == NULL) + WhitePoint = cmsD50_XYZ(); + + y = (Lab-> L + 16.0) / 116.0; + x = y + 0.002 * Lab -> a; + z = y - 0.005 * Lab -> b; + + xyz -> X = f_1(x) * WhitePoint -> X; + xyz -> Y = f_1(y) * WhitePoint -> Y; + xyz -> Z = f_1(z) * WhitePoint -> Z; + +} + +static +cmsFloat64Number L2float2(cmsUInt16Number v) +{ + return (cmsFloat64Number) v / 652.800; +} + +// the a/b part +static +cmsFloat64Number ab2float2(cmsUInt16Number v) +{ + return ((cmsFloat64Number) v / 256.0) - 128.0; +} + +static +cmsUInt16Number L2Fix2(cmsFloat64Number L) +{ + return _cmsQuickSaturateWord(L * 652.8); +} + +static +cmsUInt16Number ab2Fix2(cmsFloat64Number ab) +{ + return _cmsQuickSaturateWord((ab + 128.0) * 256.0); +} + + +static +cmsFloat64Number L2float4(cmsUInt16Number v) +{ + return (cmsFloat64Number) v / 655.35; +} + +// the a/b part +static +cmsFloat64Number ab2float4(cmsUInt16Number v) +{ + return ((cmsFloat64Number) v / 257.0) - 128.0; +} + + +void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) +{ + Lab->L = L2float2(wLab[0]); + Lab->a = ab2float2(wLab[1]); + Lab->b = ab2float2(wLab[2]); +} + + +void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) +{ + Lab->L = L2float4(wLab[0]); + Lab->a = ab2float4(wLab[1]); + Lab->b = ab2float4(wLab[2]); +} + +static +cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L) +{ + const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00; + + if (L < 0) L = 0; + if (L > L_max) L = L_max; + + return L; +} + + +static +cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab) +{ + if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2; + if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2; + + return ab; +} + +void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab) +{ + cmsCIELab Lab; + + Lab.L = Clamp_L_doubleV2(fLab ->L); + Lab.a = Clamp_ab_doubleV2(fLab ->a); + Lab.b = Clamp_ab_doubleV2(fLab ->b); + + wLab[0] = L2Fix2(Lab.L); + wLab[1] = ab2Fix2(Lab.a); + wLab[2] = ab2Fix2(Lab.b); +} + + +static +cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L) +{ + if (L < 0) L = 0; + if (L > 100.0) L = 100.0; + + return L; +} + +static +cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab) +{ + if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4; + if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4; + + return ab; +} + +static +cmsUInt16Number L2Fix4(cmsFloat64Number L) +{ + return _cmsQuickSaturateWord(L * 655.35); +} + +static +cmsUInt16Number ab2Fix4(cmsFloat64Number ab) +{ + return _cmsQuickSaturateWord((ab + 128.0) * 257.0); +} + +void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab) +{ + cmsCIELab Lab; + + Lab.L = Clamp_L_doubleV4(fLab ->L); + Lab.a = Clamp_ab_doubleV4(fLab ->a); + Lab.b = Clamp_ab_doubleV4(fLab ->b); + + wLab[0] = L2Fix4(Lab.L); + wLab[1] = ab2Fix4(Lab.a); + wLab[2] = ab2Fix4(Lab.b); +} + +// Auxiliar: convert to Radians +static +cmsFloat64Number RADIANS(cmsFloat64Number deg) +{ + return (deg * M_PI) / 180.; +} + + +// Auxiliar: atan2 but operating in degrees and returning 0 if a==b==0 +static +cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) +{ + cmsFloat64Number h; + + if (a == 0 && b == 0) + h = 0; + else + h = atan2(a, b); + + h *= (180. / M_PI); + + while (h > 360.) + h -= 360.; + + while ( h < 0) + h += 360.; + + return h; +} + + +// Auxiliar: Square +static +cmsFloat64Number Sqr(cmsFloat64Number v) +{ + return v * v; +} +// From cylindrical coordinates. No check is performed, then negative values are allowed +void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab) +{ + LCh -> L = Lab -> L; + LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5); + LCh -> h = atan2deg(Lab ->b, Lab ->a); +} + + +// To cylindrical coordinates. No check is performed, then negative values are allowed +void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh) +{ + cmsFloat64Number h = (LCh -> h * M_PI) / 180.0; + + Lab -> L = LCh -> L; + Lab -> a = LCh -> C * cos(h); + Lab -> b = LCh -> C * sin(h); +} + +// In XYZ All 3 components are encoded using 1.15 fixed point +static +cmsUInt16Number XYZ2Fix(cmsFloat64Number d) +{ + return _cmsQuickSaturateWord(d * 32768.0); +} + +void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ) +{ + cmsCIEXYZ xyz; + + xyz.X = fXYZ -> X; + xyz.Y = fXYZ -> Y; + xyz.Z = fXYZ -> Z; + + // Clamp to encodeable values. + if (xyz.Y <= 0) { + + xyz.X = 0; + xyz.Y = 0; + xyz.Z = 0; + } + + if (xyz.X > MAX_ENCODEABLE_XYZ) + xyz.X = MAX_ENCODEABLE_XYZ; + + if (xyz.X < 0) + xyz.X = 0; + + if (xyz.Y > MAX_ENCODEABLE_XYZ) + xyz.Y = MAX_ENCODEABLE_XYZ; + + if (xyz.Y < 0) + xyz.Y = 0; + + if (xyz.Z > MAX_ENCODEABLE_XYZ) + xyz.Z = MAX_ENCODEABLE_XYZ; + + if (xyz.Z < 0) + xyz.Z = 0; + + + XYZ[0] = XYZ2Fix(xyz.X); + XYZ[1] = XYZ2Fix(xyz.Y); + XYZ[2] = XYZ2Fix(xyz.Z); +} + + +// To convert from Fixed 1.15 point to cmsFloat64Number +static +cmsFloat64Number XYZ2float(cmsUInt16Number v) +{ + cmsS15Fixed16Number fix32; + + // From 1.15 to 15.16 + fix32 = v << 1; + + // From fixed 15.16 to cmsFloat64Number + return _cms15Fixed16toDouble(fix32); +} + + +void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3]) +{ + fXYZ -> X = XYZ2float(XYZ[0]); + fXYZ -> Y = XYZ2float(XYZ[1]); + fXYZ -> Z = XYZ2float(XYZ[2]); +} + + +// Returns dE on two Lab values +cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) +{ + cmsFloat64Number dL, da, db; + + dL = fabs(Lab1 -> L - Lab2 -> L); + da = fabs(Lab1 -> a - Lab2 -> a); + db = fabs(Lab1 -> b - Lab2 -> b); + + return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5); +} + + +// Return the CIE94 Delta E +cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) +{ + cmsCIELCh LCh1, LCh2; + cmsFloat64Number dE, dL, dC, dh, dhsq; + cmsFloat64Number c12, sc, sh; + + dL = fabs(Lab1 ->L - Lab2 ->L); + + cmsLab2LCh(&LCh1, Lab1); + cmsLab2LCh(&LCh2, Lab2); + + dC = fabs(LCh1.C - LCh2.C); + dE = cmsDeltaE(Lab1, Lab2); + + dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC); + if (dhsq < 0) + dh = 0; + else + dh = pow(dhsq, 0.5); + + c12 = sqrt(LCh1.C * LCh2.C); + + sc = 1.0 + (0.048 * c12); + sh = 1.0 + (0.014 * c12); + + return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh)); +} + + +// Auxiliary +static +cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab) +{ + cmsFloat64Number yt; + + if (Lab->L > 7.996969) + yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100; + else + yt = 100 * (Lab->L / 903.3); + + return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6); +} + + + +// bfd - gets BFD(1:1) difference between Lab1, Lab2 +cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) +{ + cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL, + deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd; + cmsCIELCh LCh1, LCh2; + + + lbfd1 = ComputeLBFD(Lab1); + lbfd2 = ComputeLBFD(Lab2); + deltaL = lbfd2 - lbfd1; + + cmsLab2LCh(&LCh1, Lab1); + cmsLab2LCh(&LCh2, Lab2); + + deltaC = LCh2.C - LCh1.C; + AveC = (LCh1.C+LCh2.C)/2; + Aveh = (LCh1.h+LCh2.h)/2; + + dE = cmsDeltaE(Lab1, Lab2); + + if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC))) + deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC)); + else + deltah =0; + + + dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521; + g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000)); + t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))- + 0.040*cos((2*Aveh-136)/(180/M_PI))+ + 0.070*cos((3*Aveh-31)/(180/M_PI))+ + 0.049*cos((4*Aveh+114)/(180/M_PI))- + 0.015*cos((5*Aveh-103)/(180/M_PI))); + + dh = dc*(g*t+1-g); + rh = -0.260*cos((Aveh-308)/(180/M_PI))- + 0.379*cos((2*Aveh-160)/(180/M_PI))- + 0.636*cos((3*Aveh+254)/(180/M_PI))+ + 0.226*cos((4*Aveh+140)/(180/M_PI))- + 0.194*cos((5*Aveh+280)/(180/M_PI)); + + rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000)); + rt = rh*rc; + + bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh))); + + return bfd; +} + + +// cmc - CMC(l:c) difference between Lab1, Lab2 +cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c) +{ + cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc; + cmsCIELCh LCh1, LCh2; + + if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0; + + cmsLab2LCh(&LCh1, Lab1); + cmsLab2LCh(&LCh2, Lab2); + + + dL = Lab2->L-Lab1->L; + dC = LCh2.C-LCh1.C; + + dE = cmsDeltaE(Lab1, Lab2); + + if (Sqr(dE)>(Sqr(dL)+Sqr(dC))) + dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC)); + else + dh =0; + + if ((LCh1.h > 164) && (LCh1.h < 345)) + t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI)))); + else + t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI)))); + + sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638; + sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L); + + if (Lab1->L<16) + sl = 0.511; + + f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900)); + sh = sc*(t*f+1-f); + cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh)); + + return cmc; +} + +// dE2000 The weightings KL, KC and KH can be modified to reflect the relative +// importance of lightness, chroma and hue in different industrial applications +cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, + cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh) +{ + cmsFloat64Number L1 = Lab1->L; + cmsFloat64Number a1 = Lab1->a; + cmsFloat64Number b1 = Lab1->b; + cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) ); + + cmsFloat64Number Ls = Lab2 ->L; + cmsFloat64Number as = Lab2 ->a; + cmsFloat64Number bs = Lab2 ->b; + cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) ); + + cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) )); + + cmsFloat64Number a_p = (1 + G ) * a1; + cmsFloat64Number b_p = b1; + cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p)); + cmsFloat64Number h_p = atan2deg(b_p, a_p); + + + cmsFloat64Number a_ps = (1 + G) * as; + cmsFloat64Number b_ps = bs; + cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); + cmsFloat64Number h_ps = atan2deg(b_ps, a_ps); + + cmsFloat64Number meanC_p =(C_p + C_ps) / 2; + + cmsFloat64Number hps_plus_hp = h_ps + h_p; + cmsFloat64Number hps_minus_hp = h_ps - h_p; + + cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : + (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : + (hps_plus_hp - 360)/2; + + cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : + (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : + (hps_minus_hp); + cmsFloat64Number delta_L = (Ls - L1); + cmsFloat64Number delta_C = (C_ps - C_p ); + + + cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2); + + cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30)) + + 0.24 * cos(RADIANS(2*meanh_p)) + + 0.32 * cos(RADIANS(3*meanh_p + 6)) + - 0.2 * cos(RADIANS(4*meanh_p - 63)); + + cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) ); + + cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2; + cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T; + + cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25))); + + cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0))); + + cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc; + + cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) + + Sqr(delta_C/(Sc * Kc)) + + Sqr(delta_H/(Sh * Kh)) + + Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh))); + + return deltaE00; +} + +// This function returns a number of gridpoints to be used as LUT table. It assumes same number +// of gripdpoints in all dimensions. Flags may override the choice. +int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags) +{ + int nChannels; + + // Already specified? + if (dwFlags & 0x00FF0000) { + // Yes, grab'em + return (dwFlags >> 16) & 0xFF; + } + + nChannels = cmsChannelsOf(Colorspace); + + // HighResPrecalc is maximum resolution + if (dwFlags & cmsFLAGS_HIGHRESPRECALC) { + + if (nChannels > 4) + return 7; // 7 for Hifi + + if (nChannels == 4) // 23 for CMYK + return 23; + + return 49; // 49 for RGB and others + } + + + // LowResPrecal is lower resolution + if (dwFlags & cmsFLAGS_LOWRESPRECALC) { + + if (nChannels > 4) + return 6; // 6 for more than 4 channels + + if (nChannels == 1) + return 33; // For monochrome + + return 17; // 17 for remaining + } + + // Default values + if (nChannels > 4) + return 7; // 7 for Hifi + + if (nChannels == 4) + return 17; // 17 for CMYK + + return 33; // 33 for RGB +} + + +cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, + cmsUInt16Number **White, + cmsUInt16Number **Black, + cmsUInt32Number *nOutputs) +{ + // Only most common spaces + + static cmsUInt16Number RGBblack[4] = { 0, 0, 0 }; + static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff }; + static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink + static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 }; + static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding + static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 }; + static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff }; + static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 }; + static cmsUInt16Number Grayblack[4] = { 0 }; + static cmsUInt16Number GrayWhite[4] = { 0xffff }; + + switch (Space) { + + case cmsSigGrayData: if (White) *White = GrayWhite; + if (Black) *Black = Grayblack; + if (nOutputs) *nOutputs = 1; + return TRUE; + + case cmsSigRgbData: if (White) *White = RGBwhite; + if (Black) *Black = RGBblack; + if (nOutputs) *nOutputs = 3; + return TRUE; + + case cmsSigLabData: if (White) *White = LABwhite; + if (Black) *Black = LABblack; + if (nOutputs) *nOutputs = 3; + return TRUE; + + case cmsSigCmykData: if (White) *White = CMYKwhite; + if (Black) *Black = CMYKblack; + if (nOutputs) *nOutputs = 4; + return TRUE; + + case cmsSigCmyData: if (White) *White = CMYwhite; + if (Black) *Black = CMYblack; + if (nOutputs) *nOutputs = 3; + return TRUE; + + default:; + } + + return FALSE; +} + + + +// Several utilities ------------------------------------------------------- + +// Translate from our colorspace to ICC representation + +cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation) +{ + switch (OurNotation) { + + case 1: + case PT_GRAY: return cmsSigGrayData; + + case 2: + case PT_RGB: return cmsSigRgbData; + + case PT_CMY: return cmsSigCmyData; + case PT_CMYK: return cmsSigCmykData; + case PT_YCbCr:return cmsSigYCbCrData; + case PT_YUV: return cmsSigLuvData; + case PT_XYZ: return cmsSigXYZData; + + case PT_LabV2: + case PT_Lab: return cmsSigLabData; + + case PT_YUVK: return cmsSigLuvKData; + case PT_HSV: return cmsSigHsvData; + case PT_HLS: return cmsSigHlsData; + case PT_Yxy: return cmsSigYxyData; + + case PT_MCH1: return cmsSigMCH1Data; + case PT_MCH2: return cmsSigMCH2Data; + case PT_MCH3: return cmsSigMCH3Data; + case PT_MCH4: return cmsSigMCH4Data; + case PT_MCH5: return cmsSigMCH5Data; + case PT_MCH6: return cmsSigMCH6Data; + case PT_MCH7: return cmsSigMCH7Data; + case PT_MCH8: return cmsSigMCH8Data; + + case PT_MCH9: return cmsSigMCH9Data; + case PT_MCH10: return cmsSigMCHAData; + case PT_MCH11: return cmsSigMCHBData; + case PT_MCH12: return cmsSigMCHCData; + case PT_MCH13: return cmsSigMCHDData; + case PT_MCH14: return cmsSigMCHEData; + case PT_MCH15: return cmsSigMCHFData; + + default: return (cmsColorSpaceSignature) (-1); + } +} + + +int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) +{ + switch (ProfileSpace) { + + case cmsSigGrayData: return PT_GRAY; + case cmsSigRgbData: return PT_RGB; + case cmsSigCmyData: return PT_CMY; + case cmsSigCmykData: return PT_CMYK; + case cmsSigYCbCrData:return PT_YCbCr; + case cmsSigLuvData: return PT_YUV; + case cmsSigXYZData: return PT_XYZ; + case cmsSigLabData: return PT_Lab; + case cmsSigLuvKData: return PT_YUVK; + case cmsSigHsvData: return PT_HSV; + case cmsSigHlsData: return PT_HLS; + case cmsSigYxyData: return PT_Yxy; + + case cmsSig1colorData: + case cmsSigMCH1Data: return PT_MCH1; + + case cmsSig2colorData: + case cmsSigMCH2Data: return PT_MCH2; + + case cmsSig3colorData: + case cmsSigMCH3Data: return PT_MCH3; + + case cmsSig4colorData: + case cmsSigMCH4Data: return PT_MCH4; + + case cmsSig5colorData: + case cmsSigMCH5Data: return PT_MCH5; + + case cmsSig6colorData: + case cmsSigMCH6Data: return PT_MCH6; + + case cmsSigMCH7Data: + case cmsSig7colorData:return PT_MCH7; + + case cmsSigMCH8Data: + case cmsSig8colorData:return PT_MCH8; + + case cmsSigMCH9Data: + case cmsSig9colorData:return PT_MCH9; + + case cmsSigMCHAData: + case cmsSig10colorData:return PT_MCH10; + + case cmsSigMCHBData: + case cmsSig11colorData:return PT_MCH11; + + case cmsSigMCHCData: + case cmsSig12colorData:return PT_MCH12; + + case cmsSigMCHDData: + case cmsSig13colorData:return PT_MCH13; + + case cmsSigMCHEData: + case cmsSig14colorData:return PT_MCH14; + + case cmsSigMCHFData: + case cmsSig15colorData:return PT_MCH15; + + default: return (cmsColorSpaceSignature) (-1); + } +} + + +cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) +{ + switch (ColorSpace) { + + case cmsSigGrayData: return 1; + + case cmsSig2colorData: return 2; + + case cmsSigXYZData: + case cmsSigLabData: + case cmsSigLuvData: + case cmsSigYCbCrData: + case cmsSigYxyData: + case cmsSigRgbData: + case cmsSigHsvData: + case cmsSigHlsData: + case cmsSigCmyData: + case cmsSig3colorData: return 3; + + case cmsSigLuvKData: + case cmsSigCmykData: + case cmsSig4colorData: return 4; + + case cmsSigMCH5Data: + case cmsSig5colorData: return 5; + + case cmsSigMCH6Data: + case cmsSig6colorData: return 6; + + case cmsSigMCH7Data: + case cmsSig7colorData: return 7; + + case cmsSigMCH8Data: + case cmsSig8colorData: return 8; + + case cmsSigMCH9Data: + case cmsSig9colorData: return 9; + + case cmsSigMCHAData: + case cmsSig10colorData: return 10; + + case cmsSigMCHBData: + case cmsSig11colorData: return 11; + + case cmsSigMCHCData: + case cmsSig12colorData: return 12; + + case cmsSigMCHDData: + case cmsSig13colorData: return 13; + + case cmsSigMCHEData: + case cmsSig14colorData: return 14; + + case cmsSigMCHFData: + case cmsSig15colorData: return 15; + + default: return 3; + } +} diff --git a/thirdparty/liblcms2/src/cmsplugin.c b/thirdparty/liblcms2/src/cmsplugin.c new file mode 100644 index 00000000..1fa5ff4e --- /dev/null +++ b/thirdparty/liblcms2/src/cmsplugin.c @@ -0,0 +1,612 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// ---------------------------------------------------------------------------------- +// Encoding & Decoding support functions +// ---------------------------------------------------------------------------------- + +// Little-Endian to Big-Endian + +// Adjust a word value after being readed/ before being written from/to an ICC profile +cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word) +{ +#ifndef CMS_USE_BIG_ENDIAN + + cmsUInt8Number* pByte = (cmsUInt8Number*) &Word; + cmsUInt8Number tmp; + + tmp = pByte[0]; + pByte[0] = pByte[1]; + pByte[1] = tmp; +#endif + + return Word; +} + + +// Transports to properly encoded values - note that icc profiles does use big endian notation. + +// 1 2 3 4 +// 4 3 2 1 + +cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord) +{ +#ifndef CMS_USE_BIG_ENDIAN + + cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord; + cmsUInt8Number temp1; + cmsUInt8Number temp2; + + temp1 = *pByte++; + temp2 = *pByte++; + *(pByte-1) = *pByte; + *pByte++ = temp2; + *(pByte-3) = *pByte; + *pByte = temp1; +#endif + return DWord; +} + +// 1 2 3 4 5 6 7 8 +// 8 7 6 5 4 3 2 1 + +void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord) +{ + +#ifndef CMS_USE_BIG_ENDIAN + + cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord; + cmsUInt8Number* pOut = (cmsUInt8Number*) Result; + + _cmsAssert(Result != NULL); + + pOut[7] = pIn[0]; + pOut[6] = pIn[1]; + pOut[5] = pIn[2]; + pOut[4] = pIn[3]; + pOut[3] = pIn[4]; + pOut[2] = pIn[5]; + pOut[1] = pIn[6]; + pOut[0] = pIn[7]; + +#else + + _cmsAssert(Result != NULL); + + *Result = QWord; +#endif +} + +// Auxiliar -- read 8, 16 and 32-bit numbers +cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n) +{ + cmsUInt8Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1) + return FALSE; + + if (n != NULL) *n = tmp; + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n) +{ + cmsUInt16Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1) + return FALSE; + + if (n != NULL) *n = _cmsAdjustEndianess16(tmp); + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array) +{ + cmsUInt32Number i; + + _cmsAssert(io != NULL); + + for (i=0; i < n; i++) { + + if (Array != NULL) { + if (!_cmsReadUInt16Number(io, Array + i)) return FALSE; + } + else { + if (!_cmsReadUInt16Number(io, NULL)) return FALSE; + } + + } + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; + + if (n != NULL) *n = _cmsAdjustEndianess32(tmp); + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1) + return FALSE; + + if (n != NULL) { + + tmp = _cmsAdjustEndianess32(tmp); + *n = *(cmsFloat32Number*) &tmp; + } + return TRUE; +} + + +cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) +{ + cmsUInt64Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) + return FALSE; + + if (n != NULL) _cmsAdjustEndianess64(n, tmp); + return TRUE; +} + + +cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; + + if (n != NULL) { + *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp)); + } + + return TRUE; +} + + +// Jun-21-2000: Some profiles (those that comes with W2K) comes +// with the media white (media black?) x 100. Add a sanity check + +static +void NormalizeXYZ(cmsCIEXYZ* Dest) +{ + while (Dest -> X > 2. && + Dest -> Y > 2. && + Dest -> Z > 2.) { + + Dest -> X /= 10.; + Dest -> Y /= 10.; + Dest -> Z /= 10.; + } +} + +cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ) +{ + cmsEncodedXYZNumber xyz; + + _cmsAssert(io != NULL); + + if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE; + + if (XYZ != NULL) { + + XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X)); + XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y)); + XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z)); + + NormalizeXYZ(XYZ); + } + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n) +{ + _cmsAssert(io != NULL); + + if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n) +{ + cmsUInt16Number tmp; + + _cmsAssert(io != NULL); + + tmp = _cmsAdjustEndianess16(n); + if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array) +{ + cmsUInt32Number i; + + _cmsAssert(io != NULL); + _cmsAssert(Array != NULL); + + for (i=0; i < n; i++) { + if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE; + } + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + tmp = _cmsAdjustEndianess32(n); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + + +cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + tmp = *(cmsUInt32Number*) &n; + tmp = _cmsAdjustEndianess32(tmp); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n) +{ + cmsUInt64Number tmp; + + _cmsAssert(io != NULL); + + _cmsAdjustEndianess64(&tmp, n); + if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n)); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) +{ + cmsEncodedXYZNumber xyz; + + _cmsAssert(io != NULL); + _cmsAssert(XYZ != NULL); + + xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X)); + xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y)); + xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z)); + + return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz); +} + +// from Fixed point 8.8 to double +cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) +{ + cmsUInt8Number msb, lsb; + + lsb = (cmsUInt8Number) (fixed8 & 0xff); + msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff); + + return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0)); +} + +cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) +{ + cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val); + return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF); +} + +// from Fixed point 15.16 to double +cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) +{ + cmsFloat64Number floater, sign, mid; + int Whole, FracPart; + + sign = (fix32 < 0 ? -1 : 1); + fix32 = abs(fix32); + + Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff; + FracPart = (cmsUInt16Number)(fix32 & 0xffff); + + mid = (cmsFloat64Number) FracPart / 65536.0; + floater = (cmsFloat64Number) Whole + mid; + + return sign * floater; +} + +// from double to Fixed point 15.16 +cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v) +{ + return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5)); +} + +// Date/Time functions + +void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest) +{ + + _cmsAssert(Dest != NULL); + _cmsAssert(Source != NULL); + + Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds); + Dest->tm_min = _cmsAdjustEndianess16(Source->minutes); + Dest->tm_hour = _cmsAdjustEndianess16(Source->hours); + Dest->tm_mday = _cmsAdjustEndianess16(Source->day); + Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1; + Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900; + Dest->tm_wday = -1; + Dest->tm_yday = -1; + Dest->tm_isdst = 0; +} + +void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source) +{ + _cmsAssert(Dest != NULL); + _cmsAssert(Source != NULL); + + Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec); + Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min); + Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour); + Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday); + Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1)); + Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900)); +} + +// Read base and return type base +cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io) +{ + _cmsTagBase Base; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1) + return (cmsTagTypeSignature) 0; + + return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig); +} + +// Setup base marker +cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig) +{ + _cmsTagBase Base; + + _cmsAssert(io != NULL); + + Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig); + memset(&Base.reserved, 0, sizeof(Base.reserved)); + return io -> Write(io, sizeof(_cmsTagBase), &Base); +} + +cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io) +{ + cmsUInt8Number Buffer[4]; + cmsUInt32Number NextAligned, At; + cmsUInt32Number BytesToNextAlignedPos; + + _cmsAssert(io != NULL); + + At = io -> Tell(io); + NextAligned = _cmsALIGNLONG(At); + BytesToNextAlignedPos = NextAligned - At; + if (BytesToNextAlignedPos == 0) return TRUE; + if (BytesToNextAlignedPos > 4) return FALSE; + + return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1); +} + +cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io) +{ + cmsUInt8Number Buffer[4]; + cmsUInt32Number NextAligned, At; + cmsUInt32Number BytesToNextAlignedPos; + + _cmsAssert(io != NULL); + + At = io -> Tell(io); + NextAligned = _cmsALIGNLONG(At); + BytesToNextAlignedPos = NextAligned - At; + if (BytesToNextAlignedPos == 0) return TRUE; + if (BytesToNextAlignedPos > 4) return FALSE; + + memset(Buffer, 0, BytesToNextAlignedPos); + return io -> Write(io, BytesToNextAlignedPos, Buffer); +} + + +// To deal with text streams. 2K at most +cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) +{ + va_list args; + int len; + cmsUInt8Number Buffer[2048]; + cmsBool rc; + + _cmsAssert(io != NULL); + _cmsAssert(frm != NULL); + + va_start(args, frm); + + len = vsnprintf((char*) Buffer, 2047, frm, args); + if (len < 0) return FALSE; // Truncated, which is a fatal error for us + + rc = io ->Write(io, len, Buffer); + + va_end(args); + + return rc; +} + + +// Plugin memory management ------------------------------------------------------------------------------------------------- + +static _cmsSubAllocator* PluginPool = NULL; + +// Specialized malloc for plug-ins, that is freed upon exit. +void* _cmsPluginMalloc(cmsUInt32Number size) +{ + if (PluginPool == NULL) + PluginPool = _cmsCreateSubAlloc(0, 4*1024); + + return _cmsSubAlloc(PluginPool, size); +} + + +// Main plug-in dispatcher +cmsBool CMSEXPORT cmsPlugin(void* Plug_in) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) Plug_in; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic != cmsPluginMagicNumber) { + cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); + return FALSE; + } + + if (Plugin ->ExpectedVersion > LCMS_VERSION) { + cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", + Plugin ->ExpectedVersion, LCMS_VERSION); + return FALSE; + } + + switch (Plugin -> Type) { + + case cmsPluginMemHandlerSig: + if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE; + break; + + case cmsPluginInterpolationSig: + if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE; + break; + + case cmsPluginTagTypeSig: + if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE; + break; + + case cmsPluginTagSig: + if (!_cmsRegisterTagPlugin(Plugin)) return FALSE; + break; + + case cmsPluginFormattersSig: + if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE; + break; + + case cmsPluginRenderingIntentSig: + if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE; + break; + + case cmsPluginParametricCurveSig: + if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE; + break; + + case cmsPluginMultiProcessElementSig: + if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE; + break; + + case cmsPluginOptimizationSig: + if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE; + break; + + default: + cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); + return FALSE; + } + } + + // Keep a reference to the plug-in + return TRUE; +} + + +// Revert all plug-ins to default +void CMSEXPORT cmsUnregisterPlugins(void) +{ + _cmsRegisterMemHandlerPlugin(NULL); + _cmsRegisterInterpPlugin(NULL); + _cmsRegisterTagTypePlugin(NULL); + _cmsRegisterTagPlugin(NULL); + _cmsRegisterFormattersPlugin(NULL); + _cmsRegisterRenderingIntentPlugin(NULL); + _cmsRegisterParametricCurvesPlugin(NULL); + _cmsRegisterMultiProcessElementPlugin(NULL); + _cmsRegisterOptimizationPlugin(NULL); + + if (PluginPool != NULL) + _cmsSubAllocDestroy(PluginPool); + + PluginPool = NULL; +} diff --git a/thirdparty/liblcms2/src/cmsps2.c b/thirdparty/liblcms2/src/cmsps2.c new file mode 100644 index 00000000..b41f58ff --- /dev/null +++ b/thirdparty/liblcms2/src/cmsps2.c @@ -0,0 +1,1595 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2008 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// PostScript ColorRenderingDictionary and ColorSpaceArray + + +#define MAXPSCOLS 60 // Columns on tables + +/* + Implementation + -------------- + + PostScript does use XYZ as its internal PCS. But since PostScript + interpolation tables are limited to 8 bits, I use Lab as a way to + improve the accuracy, favoring perceptual results. So, for the creation + of each CRD, CSA the profiles are converted to Lab via a device + link between profile -> Lab or Lab -> profile. The PS code necessary to + convert Lab <-> XYZ is also included. + + + + Color Space Arrays (CSA) + ================================================================================== + + In order to obtain precision, code chooses between three ways to implement + the device -> XYZ transform. These cases identifies monochrome profiles (often + implemented as a set of curves), matrix-shaper and Pipeline-based. + + Monochrome + ----------- + + This is implemented as /CIEBasedA CSA. The prelinearization curve is + placed into /DecodeA section, and matrix equals to D50. Since here is + no interpolation tables, I do the conversion directly to XYZ + + NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT + flag is forced on such profiles. + + [ /CIEBasedA + << + /DecodeA { transfer function } bind + /MatrixA [D50] + /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] + /WhitePoint [D50] + /BlackPoint [BP] + /RenderingIntent (intent) + >> + ] + + On simpler profiles, the PCS is already XYZ, so no conversion is required. + + + Matrix-shaper based + ------------------- + + This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig + of profile implementation. Since here there are no interpolation tables, I do + the conversion directly to XYZ + + + + [ /CIEBasedABC + << + /DecodeABC [ {transfer1} {transfer2} {transfer3} ] + /MatrixABC [Matrix] + /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] + /DecodeLMN [ { / 2} dup dup ] + /WhitePoint [D50] + /BlackPoint [BP] + /RenderingIntent (intent) + >> + ] + + + CLUT based + ---------- + + Lab is used in such cases. + + [ /CIEBasedDEF + << + /DecodeDEF [ ] + /Table [ p p p [<...>]] + /RangeABC [ 0 1 0 1 0 1] + /DecodeABC[ ] + /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] + % -128/500 1+127/500 0 1 -127/200 1+128/200 + /MatrixABC [ 1 1 1 1 0 0 0 0 -1] + /WhitePoint [D50] + /BlackPoint [BP] + /RenderingIntent (intent) + ] + + + Color Rendering Dictionaries (CRD) + ================================== + These are always implemented as CLUT, and always are using Lab. Since CRD are expected to + be used as resources, the code adds the definition as well. + + << + /ColorRenderingType 1 + /WhitePoint [ D50 ] + /BlackPoint [BP] + /MatrixPQR [ Bradford ] + /RangePQR [-0.125 1.375 -0.125 1.375 -0.125 1.375 ] + /TransformPQR [ + {4 index 3 get div 2 index 3 get mul exch pop exch pop exch pop exch pop } bind + {4 index 4 get div 2 index 4 get mul exch pop exch pop exch pop exch pop } bind + {4 index 5 get div 2 index 5 get mul exch pop exch pop exch pop exch pop } bind + ] + /MatrixABC <...> + /EncodeABC <...> + /RangeABC <.. used for XYZ -> Lab> + /EncodeLMN + /RenderTable [ p p p [<...>]] + + /RenderingIntent (Perceptual) + >> + /Current exch /ColorRendering defineresource pop + + + The following stages are used to convert from XYZ to Lab + -------------------------------------------------------- + + Input is given at LMN stage on X, Y, Z + + Encode LMN gives us f(X/Xn), f(Y/Yn), f(Z/Zn) + + /EncodeLMN [ + + { 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind + { 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind + { 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind + + ] + + + MatrixABC is used to compute f(Y/Yn), f(X/Xn) - f(Y/Yn), f(Y/Yn) - f(Z/Zn) + + | 0 1 0| + | 1 -1 0| + | 0 1 -1| + + /MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ] + + EncodeABC finally gives Lab values. + + /EncodeABC [ + { 116 mul 16 sub 100 div } bind + { 500 mul 128 add 255 div } bind + { 200 mul 128 add 255 div } bind + ] + + The following stages are used to convert Lab to XYZ + ---------------------------------------------------- + + /RangeABC [ 0 1 0 1 0 1] + /DecodeABC [ { 100 mul 16 add 116 div } bind + { 255 mul 128 sub 500 div } bind + { 255 mul 128 sub 200 div } bind + ] + + /MatrixABC [ 1 1 1 1 0 0 0 0 -1] + /DecodeLMN [ + {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind + {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind + {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind + ] + + +*/ + +/* + + PostScript algorithms discussion. + ========================================================================================================= + + 1D interpolation algorithm + + + 1D interpolation (float) + ------------------------ + + val2 = Domain * Value; + + cell0 = (int) floor(val2); + cell1 = (int) ceil(val2); + + rest = val2 - cell0; + + y0 = LutTable[cell0] ; + y1 = LutTable[cell1] ; + + y = y0 + (y1 - y0) * rest; + + + + PostScript code Stack + ================================================ + + { % v + + [array] % v tab + dup % v tab tab + length 1 sub % v tab dom + + 3 -1 roll % tab dom v + + mul % tab val2 + dup % tab val2 val2 + dup % tab val2 val2 val2 + floor cvi % tab val2 val2 cell0 + exch % tab val2 cell0 val2 + ceiling cvi % tab val2 cell0 cell1 + + 3 index % tab val2 cell0 cell1 tab + exch % tab val2 cell0 tab cell1 + get % tab val2 cell0 y1 + + 4 -1 roll % val2 cell0 y1 tab + 3 -1 roll % val2 y1 tab cell0 + get % val2 y1 y0 + + dup % val2 y1 y0 y0 + 3 1 roll % val2 y0 y1 y0 + + sub % val2 y0 (y1-y0) + 3 -1 roll % y0 (y1-y0) val2 + dup % y0 (y1-y0) val2 val2 + floor cvi % y0 (y1-y0) val2 floor(val2) + sub % y0 (y1-y0) rest + mul % y0 t1 + add % y + 65535 div % result + + } bind + + +*/ + + +// This struct holds the memory block currently being write +typedef struct { + _cmsStageCLutData* Pipeline; + cmsIOHANDLER* m; + + int FirstComponent; + int SecondComponent; + + const char* PreMaj; + const char* PostMaj; + const char* PreMin; + const char* PostMin; + + int FixWhite; // Force mapping of pure white + + cmsColorSpaceSignature ColorSpace; // ColorSpace of profile + + +} cmsPsSamplerCargo; + +static int _cmsPSActualColumn = 0; + + +// Convert to byte +static +cmsUInt8Number Word2Byte(cmsUInt16Number w) +{ + return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5); +} + + +// Convert to byte (using ICC2 notation) +/* +static +cmsUInt8Number L2Byte(cmsUInt16Number w) +{ + int ww = w + 0x0080; + + if (ww > 0xFFFF) return 0xFF; + + return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF); +} +*/ + +// Write a cooked byte + +static +void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b) +{ + _cmsIOPrintf(m, "%02x", b); + _cmsPSActualColumn += 2; + + if (_cmsPSActualColumn > MAXPSCOLS) { + + _cmsIOPrintf(m, "\n"); + _cmsPSActualColumn = 0; + } +} + +// ----------------------------------------------------------------- PostScript generation + + +// Removes offending Carriage returns +static +char* RemoveCR(const char* txt) +{ + static char Buffer[2048]; + char* pt; + + strncpy(Buffer, txt, 2047); + Buffer[2047] = 0; + for (pt = Buffer; *pt; pt++) + if (*pt == '\n' || *pt == '\r') *pt = ' '; + + return Buffer; + +} + +static +void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile) +{ + time_t timer; + cmsMLU *Description, *Copyright; + char DescASCII[256], CopyrightASCII[256]; + + time(&timer); + + Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag); + Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag); + + DescASCII[0] = DescASCII[255] = 0; + CopyrightASCII[0] = CopyrightASCII[255] = 0; + + if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255); + if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255); + + _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n"); + _cmsIOPrintf(m, "%%\n"); + _cmsIOPrintf(m, "%% %s\n", Title); + _cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII)); + _cmsIOPrintf(m, "%% %s\n", RemoveCR(CopyrightASCII)); + _cmsIOPrintf(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!! + _cmsIOPrintf(m, "%%\n"); + _cmsIOPrintf(m, "%%%%BeginResource\n"); + +} + + +// Emits White & Black point. White point is always D50, Black point is the device +// Black point adapted to D50. + +static +void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint) +{ + + _cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X, + BlackPoint -> Y, + BlackPoint -> Z); + + _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X, + cmsD50_XYZ()->Y, + cmsD50_XYZ()->Z); +} + + +static +void EmitRangeCheck(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if " + "dup 1.0 gt { pop 1.0 } if "); + +} + +// Does write the intent + +static +void EmitIntent(cmsIOHANDLER* m, int RenderingIntent) +{ + const char *intent; + + switch (RenderingIntent) { + + case INTENT_PERCEPTUAL: intent = "Perceptual"; break; + case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break; + case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break; + case INTENT_SATURATION: intent = "Saturation"; break; + + default: intent = "Undefined"; break; + } + + _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent ); +} + +// +// Convert L* to Y +// +// Y = Yn*[ (L* + 16) / 116] ^ 3 if (L*) >= 6 / 29 +// = Yn*( L* / 116) / 7.787 if (L*) < 6 / 29 +// + +/* +static +void EmitL2Y(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, + "{ " + "100 mul 16 add 116 div " // (L * 100 + 16) / 116 + "dup 6 29 div ge " // >= 6 / 29 ? + "{ dup dup mul mul } " // yes, ^3 and done + "{ 4 29 div sub 108 841 div mul } " // no, slope limiting + "ifelse } bind "); +} +*/ + + +// Lab -> XYZ, see the discussion above + +static +void EmitLab2XYZ(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n"); + _cmsIOPrintf(m, "/DecodeABC [\n"); + _cmsIOPrintf(m, "{100 mul 16 add 116 div } bind\n"); + _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n"); + _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n"); + _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n"); + _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); + _cmsIOPrintf(m, "/DecodeLMN [\n"); + _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n"); + _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n"); + _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n"); + _cmsIOPrintf(m, "]\n"); +} + + + +// Outputs a table of words. It does use 16 bits + +static +void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) +{ + cmsUInt32Number i; + cmsFloat64Number gamma; + + + if (Table ->nEntries <= 0) return; // Empty table + + // Suppress whole if identity + if (cmsIsToneCurveLinear(Table)) return; + + // Check if is really an exponential. If so, emit "exp" + gamma = cmsEstimateGamma(Table, 0.001); + if (gamma > 0) { + _cmsIOPrintf(m, "{ %g exp } bind ", gamma); + return; + } + + _cmsIOPrintf(m, "{ "); + + // Bounds check + EmitRangeCheck(m); + + // Emit intepolation code + + // PostScript code Stack + // =============== ======================== + // v + _cmsIOPrintf(m, " ["); + + for (i=0; i < Table->nEntries; i++) { + _cmsIOPrintf(m, "%d ", Table->Table16[i]); + } + + _cmsIOPrintf(m, "] "); // v tab + + _cmsIOPrintf(m, "dup "); // v tab tab + _cmsIOPrintf(m, "length 1 sub "); // v tab dom + _cmsIOPrintf(m, "3 -1 roll "); // tab dom v + _cmsIOPrintf(m, "mul "); // tab val2 + _cmsIOPrintf(m, "dup "); // tab val2 val2 + _cmsIOPrintf(m, "dup "); // tab val2 val2 val2 + _cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0 + _cmsIOPrintf(m, "exch "); // tab val2 cell0 val2 + _cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1 + _cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab + _cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1 + _cmsIOPrintf(m, "get "); // tab val2 cell0 y1 + _cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab + _cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0 + _cmsIOPrintf(m, "get "); // val2 y1 y0 + _cmsIOPrintf(m, "dup "); // val2 y1 y0 y0 + _cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0 + _cmsIOPrintf(m, "sub "); // val2 y0 (y1-y0) + _cmsIOPrintf(m, "3 -1 roll "); // y0 (y1-y0) val2 + _cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2 + _cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2) + _cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest + _cmsIOPrintf(m, "mul "); // y0 t1 + _cmsIOPrintf(m, "add "); // y + _cmsIOPrintf(m, "65535 div "); // result + + _cmsIOPrintf(m, " } bind "); +} + + +// Compare gamma table + +static +cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries) +{ + return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0; +} + + +// Does write a set of gamma curves + +static +void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) +{ + int i; + + for( i=0; i < n; i++ ) + { + if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) { + + _cmsIOPrintf(m, "dup "); + } + else { + Emit1Gamma(m, g[i]); + } + } + +} + + + + + +// Following code dumps a LUT onto memory stream + + +// This is the sampler. Intended to work in SAMPLER_INSPECT mode, +// that is, the callback will be called for each knot with +// +// In[] The grid location coordinates, normalized to 0..ffff +// Out[] The Pipeline values, normalized to 0..ffff +// +// Returning a value other than 0 does terminate the sampling process +// +// Each row contains Pipeline values for all but first component. So, I +// detect row changing by keeping a copy of last value of first +// component. -1 is used to mark begining of whole block. + +static +int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo; + cmsUInt32Number i; + + + if (sc -> FixWhite) { + + if (In[0] == 0xFFFF) { // Only in L* = 100, ab = [-8..8] + + if ((In[1] >= 0x7800 && In[1] <= 0x8800) && + (In[2] >= 0x7800 && In[2] <= 0x8800)) { + + cmsUInt16Number* Black; + cmsUInt16Number* White; + cmsUInt32Number nOutputs; + + if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs)) + return 0; + + for (i=0; i < nOutputs; i++) + Out[i] = White[i]; + } + + + } + } + + + // Hadle the parenthesis on rows + + if (In[0] != sc ->FirstComponent) { + + if (sc ->FirstComponent != -1) { + + _cmsIOPrintf(sc ->m, sc ->PostMin); + sc ->SecondComponent = -1; + _cmsIOPrintf(sc ->m, sc ->PostMaj); + } + + // Begin block + _cmsPSActualColumn = 0; + + _cmsIOPrintf(sc ->m, sc ->PreMaj); + sc ->FirstComponent = In[0]; + } + + + if (In[1] != sc ->SecondComponent) { + + if (sc ->SecondComponent != -1) { + + _cmsIOPrintf(sc ->m, sc ->PostMin); + } + + _cmsIOPrintf(sc ->m, sc ->PreMin); + sc ->SecondComponent = In[1]; + } + + // Dump table. + + for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) { + + cmsUInt16Number wWordOut = Out[i]; + cmsUInt8Number wByteOut; // Value as byte + + + // We always deal with Lab4 + + wByteOut = Word2Byte(wWordOut); + WriteByte(sc -> m, wByteOut); + } + + return 1; +} + +// Writes a Pipeline on memstream. Could be 8 or 16 bits based + +static +void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, + const char* PostMaj, + const char* PreMin, + const char* PostMin, + int FixWhite, + cmsColorSpaceSignature ColorSpace) +{ + cmsUInt32Number i; + cmsPsSamplerCargo sc; + + sc.FirstComponent = -1; + sc.SecondComponent = -1; + sc.Pipeline = (_cmsStageCLutData *) mpe ->Data; + sc.m = m; + sc.PreMaj = PreMaj; + sc.PostMaj= PostMaj; + + sc.PreMin = PreMin; + sc.PostMin = PostMin; + sc.FixWhite = FixWhite; + sc.ColorSpace = ColorSpace; + + _cmsIOPrintf(m, "["); + + for (i=0; i < sc.Pipeline->Params->nInputs; i++) + _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); + + _cmsIOPrintf(m, " [\n"); + + cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT); + + _cmsIOPrintf(m, PostMin); + _cmsIOPrintf(m, PostMaj); + _cmsIOPrintf(m, "] "); + +} + + +// Dumps CIEBasedA Color Space Array + +static +int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) +{ + + _cmsIOPrintf(m, "[ /CIEBasedA\n"); + _cmsIOPrintf(m, " <<\n"); + + _cmsIOPrintf(m, "/DecodeA "); + + Emit1Gamma(m, Curve); + + _cmsIOPrintf(m, " \n"); + + _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); + _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, INTENT_PERCEPTUAL); + + _cmsIOPrintf(m, ">>\n"); + _cmsIOPrintf(m, "]\n"); + + return 1; +} + + +// Dumps CIEBasedABC Color Space Array + +static +int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint) +{ + int i; + + _cmsIOPrintf(m, "[ /CIEBasedABC\n"); + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "/DecodeABC [ "); + + EmitNGamma(m, 3, CurveSet); + + _cmsIOPrintf(m, "]\n"); + + _cmsIOPrintf(m, "/MatrixABC [ " ); + + for( i=0; i < 3; i++ ) { + + _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0], + Matrix[i + 3*1], + Matrix[i + 3*2]); + } + + + _cmsIOPrintf(m, "]\n"); + + _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, INTENT_PERCEPTUAL); + + _cmsIOPrintf(m, ">>\n"); + _cmsIOPrintf(m, "]\n"); + + + return 1; +} + + +static +int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint) +{ + const char* PreMaj; + const char* PostMaj; + const char* PreMin, *PostMin; + cmsStage* mpe; + + mpe = Pipeline ->Elements; + + + switch (cmsStageInputChannels(mpe)) { + case 3: + + _cmsIOPrintf(m, "[ /CIEBasedDEF\n"); + PreMaj ="<"; + PostMaj= ">\n"; + PreMin = PostMin = ""; + break; + case 4: + _cmsIOPrintf(m, "[ /CIEBasedDEFG\n"); + PreMaj = "["; + PostMaj = "]\n"; + PreMin = "<"; + PostMin = ">\n"; + break; + default: + return 0; + + } + + _cmsIOPrintf(m, "<<\n"); + + if (cmsStageType(mpe) == cmsSigCurveSetElemType) { + + _cmsIOPrintf(m, "/DecodeDEF [ "); + EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe)); + _cmsIOPrintf(m, "]\n"); + + mpe = mpe ->Next; + } + + + + if (cmsStageType(mpe) == cmsSigCLutElemType) { + + _cmsIOPrintf(m, "/Table "); + WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0); + _cmsIOPrintf(m, "]\n"); + } + + EmitLab2XYZ(m); + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, Intent); + + _cmsIOPrintf(m, " >>\n"); + _cmsIOPrintf(m, "]\n"); + + + return 1; +} + +// Generates a curve from a gray profile + +static +cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent) +{ + cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); + cmsHPROFILE hXYZ = cmsCreateXYZProfile(); + cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE); + int i; + + for (i=0; i < 256; i++) { + + cmsUInt8Number Gray = (cmsUInt8Number) i; + cmsCIEXYZ XYZ; + + cmsDoTransform(xform, &Gray, &XYZ, 1); + + Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); + } + + cmsDeleteTransform(xform); + cmsCloseProfile(hXYZ); + return Out; +} + + + +// Because PostScript has only 8 bits in /Table, we should use +// a more perceptually uniform space... I do choose Lab. + +static +int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) +{ + cmsHPROFILE hLab; + cmsHTRANSFORM xform; + cmsUInt32Number nChannels; + cmsUInt32Number InputFormat; + int rc; + cmsHPROFILE Profiles[2]; + cmsCIEXYZ BlackPointAdaptedToD50; + + // Does create a device-link based transform. + // The DeviceLink is next dumped as working CSA. + + InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); + nChannels = T_CHANNELS(InputFormat); + + + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); + + // Adjust output to Lab4 + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + + Profiles[0] = hProfile; + Profiles[1] = hLab; + + xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); + cmsCloseProfile(hLab); + + if (xform == NULL) { + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); + return 0; + } + + // Only 1, 3 and 4 channels are allowed + + switch (nChannels) { + + case 1: { + cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); + EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); + cmsFreeToneCurve(Gray2Y); + } + break; + + case 3: + case 4: { + cmsUInt32Number OutFrm = TYPE_Lab_16; + cmsPipeline* DeviceLink; + _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; + + DeviceLink = cmsPipelineDup(v ->Lut); + if (DeviceLink == NULL) return 0; + + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); + + rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); + cmsPipelineFree(DeviceLink); + } + break; + + default: + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels); + return 0; + } + + + cmsDeleteTransform(xform); + + return 1; +} + +static +cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe) +{ + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + + return Data -> Double; +} + + +// Does create CSA based on matrix-shaper. Allowed types are gray and RGB based + +static +int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper) +{ + cmsColorSpaceSignature ColorSpace; + int rc; + cmsCIEXYZ BlackPointAdaptedToD50; + + ColorSpace = cmsGetColorSpace(hProfile); + + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0); + + if (ColorSpace == cmsSigGrayData) { + + cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper); + rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); + + } + else + if (ColorSpace == cmsSigRgbData) { + + cmsMAT3 Mat; + int i, j; + + memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat)); + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ; + + rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat, + _cmsStageGetPtrToCurveSet(Shaper), + &BlackPointAdaptedToD50); + } + else { + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace."); + return 0; + } + + return rc; +} + + + +// Creates a PostScript color list from a named profile data. +// This is a HP extension, and it works in Lab instead of XYZ + +static +int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) +{ + cmsHTRANSFORM xform; + cmsHPROFILE hLab; + int i, nColors; + char ColorName[32]; + cmsNAMEDCOLORLIST* NamedColorList; + + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); + if (xform == NULL) return 0; + + NamedColorList = cmsGetNamedColorList(xform); + if (NamedColorList == NULL) return 0; + + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); + _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); + _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); + + nColors = cmsNamedColorCount(NamedColorList); + + + for (i=0; i < nColors; i++) { + + cmsUInt16Number In[1]; + cmsCIELab Lab; + + In[0] = (cmsUInt16Number) i; + + if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) + continue; + + cmsDoTransform(xform, In, &Lab, 1); + _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); + } + + + + _cmsIOPrintf(m, ">>\n"); + + cmsDeleteTransform(xform); + cmsCloseProfile(hLab); + return 1; +} + + +// Does create a Color Space Array on XYZ colorspace for PostScript usage +static +cmsUInt32Number GenerateCSA(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* mem) +{ + cmsUInt32Number dwBytesUsed; + cmsPipeline* lut = NULL; + cmsStage* Matrix, *Shaper; + + + // Is a named color profile? + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error; + } + else { + + + // Any profile class are allowed (including devicelink), but + // output (PCS) colorspace must be XYZ or Lab + cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); + + if (ColorSpace != cmsSigXYZData && + ColorSpace != cmsSigLabData) { + + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); + goto Error; + } + + + // Read the lut with all necessary conversion stages + lut = _cmsReadInputLUT(hProfile, Intent); + if (lut == NULL) goto Error; + + + // Tone curves + matrix can be implemented without any LUT + if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) { + + if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error; + + } + else { + // We need a LUT for the rest + if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; + } + } + + + // Done, keep memory usage + dwBytesUsed = mem ->UsedSpace; + + // Get rid of LUT + if (lut != NULL) cmsPipelineFree(lut); + + // Finally, return used byte count + return dwBytesUsed; + +Error: + if (lut != NULL) cmsPipelineFree(lut); + return 0; +} + +// ------------------------------------------------------ Color Rendering Dictionary (CRD) + + + +/* + + Black point compensation plus chromatic adaptation: + + Step 1 - Chromatic adaptation + ============================= + + WPout + X = ------- PQR + Wpin + + Step 2 - Black point compensation + ================================= + + (WPout - BPout)*X - WPout*(BPin - BPout) + out = --------------------------------------- + WPout - BPin + + + Algorithm discussion + ==================== + + TransformPQR(WPin, BPin, WPout, BPout, PQR) + + Wpin,etc= { Xws Yws Zws Pws Qws Rws } + + + Algorithm Stack 0...n + =========================================================== + PQR BPout WPout BPin WPin + 4 index 3 get WPin PQR BPout WPout BPin WPin + div (PQR/WPin) BPout WPout BPin WPin + 2 index 3 get WPout (PQR/WPin) BPout WPout BPin WPin + mult WPout*(PQR/WPin) BPout WPout BPin WPin + + 2 index 3 get WPout WPout*(PQR/WPin) BPout WPout BPin WPin + 2 index 3 get BPout WPout WPout*(PQR/WPin) BPout WPout BPin WPin + sub (WPout-BPout) WPout*(PQR/WPin) BPout WPout BPin WPin + mult (WPout-BPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + + 2 index 3 get WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + 4 index 3 get BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + 3 index 3 get BPout BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + + sub (BPin-BPout) WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + mult (BPin-BPout)*WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + sub (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + + 3 index 3 get BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + 3 index 3 get WPout BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + exch + sub (WPout-BPin) (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + div + + exch pop + exch pop + exch pop + exch pop + +*/ + + +static +void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute) +{ + + + if (lIsAbsolute) { + + // For absolute colorimetric intent, encode back to relative + // and generate a relative Pipeline + + // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) + + cmsCIEXYZ White; + + _cmsReadMediaWhitePoint(&White, hProfile); + + _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); + _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); + + _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n" + "/TransformPQR [\n" + "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", + White.X, White.Y, White.Z); + return; + } + + + _cmsIOPrintf(m,"%% Bradford Cone Space\n" + "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n"); + + _cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); + + + // No BPC + + if (!DoBPC) { + + _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n" + "/TransformPQR [\n" + "{exch pop exch 3 get mul exch pop exch 3 get div} bind\n" + "{exch pop exch 4 get mul exch pop exch 4 get div} bind\n" + "{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n"); + } else { + + // BPC + + _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n" + "/TransformPQR [\n"); + + _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul " + "2 index 3 get 2 index 3 get sub mul " + "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub " + "3 index 3 get 3 index 3 get exch sub div " + "exch pop exch pop exch pop exch pop } bind\n"); + + _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul " + "2 index 4 get 2 index 4 get sub mul " + "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub " + "3 index 4 get 3 index 4 get exch sub div " + "exch pop exch pop exch pop exch pop } bind\n"); + + _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul " + "2 index 5 get 2 index 5 get sub mul " + "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub " + "3 index 5 get 3 index 5 get exch sub div " + "exch pop exch pop exch pop exch pop } bind\n]\n"); + + } + + +} + + +static +void EmitXYZ2Lab(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); + _cmsIOPrintf(m, "/EncodeLMN [\n"); + _cmsIOPrintf(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); + _cmsIOPrintf(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); + _cmsIOPrintf(m, "{ 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); + _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n"); + _cmsIOPrintf(m, "/EncodeABC [\n"); + + + _cmsIOPrintf(m, "{ 116 mul 16 sub 100 div } bind\n"); + _cmsIOPrintf(m, "{ 500 mul 128 add 256 div } bind\n"); + _cmsIOPrintf(m, "{ 200 mul 128 add 256 div } bind\n"); + + + _cmsIOPrintf(m, "]\n"); + + +} + +// Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces +// I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted +// space on 3D CLUT, but since space seems not to be a problem here, 33 points +// would give a reasonable accurancy. Note also that CRD tables must operate in +// 8 bits. + +static +int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) +{ + cmsHPROFILE hLab; + cmsHTRANSFORM xform; + int i, nChannels; + cmsUInt32Number OutputFormat; + _cmsTRANSFORM* v; + cmsPipeline* DeviceLink; + cmsHPROFILE Profiles[3]; + cmsCIEXYZ BlackPointAdaptedToD50; + cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); + cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); + cmsUInt32Number InFrm = TYPE_Lab_16; + int RelativeEncodingIntent; + cmsColorSpaceSignature ColorSpace; + + + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + if (hLab == NULL) return 0; + + OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); + nChannels = T_CHANNELS(OutputFormat); + + ColorSpace = cmsGetColorSpace(hProfile); + + // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. + + RelativeEncodingIntent = Intent; + if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) + RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; + + + // Use V4 Lab always + Profiles[0] = hLab; + Profiles[1] = hProfile; + + xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, + Profiles, 2, TYPE_Lab_DBL, + OutputFormat, RelativeEncodingIntent, 0); + cmsCloseProfile(hLab); + + if (xform == NULL) { + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); + return 0; + } + + // Get a copy of the internal devicelink + v = (_cmsTRANSFORM*) xform; + DeviceLink = cmsPipelineDup(v ->Lut); + if (DeviceLink == NULL) return 0; + + + // We need a CLUT + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); + + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "/ColorRenderingType 1\n"); + + + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); + + // Emit headers, etc. + EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); + EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); + EmitXYZ2Lab(m); + + + // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab + // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, + // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to + // zero. This would sacrifice a bit of highlights, but failure to do so would cause + // scum dot. Ouch. + + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + lFixWhite = FALSE; + + _cmsIOPrintf(m, "/RenderTable "); + + + WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); + + _cmsIOPrintf(m, " %d {} bind ", nChannels); + + for (i=1; i < nChannels; i++) + _cmsIOPrintf(m, "dup "); + + _cmsIOPrintf(m, "]\n"); + + + EmitIntent(m, Intent); + + _cmsIOPrintf(m, ">>\n"); + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n"); + } + + cmsPipelineFree(DeviceLink); + cmsDeleteTransform(xform); + + return 1; +} + + +// Builds a ASCII string containing colorant list in 0..1.0 range +static +void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[]) +{ + char Buff[32]; + int j; + + Colorant[0] = 0; + if (nColorant > cmsMAXCHANNELS) + nColorant = cmsMAXCHANNELS; + + for (j=0; j < nColorant; j++) { + + sprintf(Buff, "%.3f", Out[j] / 65535.0); + strcat(Colorant, Buff); + if (j < nColorant -1) + strcat(Colorant, " "); + + } +} + + +// Creates a PostScript color list from a named profile data. +// This is a HP extension. + +static +int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags) +{ + cmsHTRANSFORM xform; + int i, nColors, nColorant; + cmsUInt32Number OutputFormat; + char ColorName[32]; + char Colorant[128]; + cmsNAMEDCOLORLIST* NamedColorList; + + + OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE); + nColorant = T_CHANNELS(OutputFormat); + + + xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags); + if (xform == NULL) return 0; + + + NamedColorList = cmsGetNamedColorList(xform); + if (NamedColorList == NULL) return 0; + + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); + _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); + _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); + + nColors = cmsNamedColorCount(NamedColorList); + + for (i=0; i < nColors; i++) { + + cmsUInt16Number In[1]; + cmsUInt16Number Out[cmsMAXCHANNELS]; + + In[0] = (cmsUInt16Number) i; + + if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) + continue; + + cmsDoTransform(xform, In, Out, 1); + BuildColorantList(Colorant, nColorant, Out); + _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant); + } + + _cmsIOPrintf(m, " >>"); + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n"); + } + + cmsDeleteTransform(xform); + return 1; +} + + + +// This one does create a Color Rendering Dictionary. +// CRD are always LUT-Based, no matter if profile is +// implemented as matrix-shaper. + +static +cmsUInt32Number GenerateCRD(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number dwFlags, + cmsIOHANDLER* mem) +{ + cmsUInt32Number dwBytesUsed; + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile); + } + + + // Is a named color profile? + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { + return 0; + } + } + else { + + // CRD are always implemented as LUT + + if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { + return 0; + } + } + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + _cmsIOPrintf(mem, "%%%%EndResource\n"); + _cmsIOPrintf(mem, "\n%% CRD End\n"); + } + + // Done, keep memory usage + dwBytesUsed = mem ->UsedSpace; + + // Finally, return used byte count + return dwBytesUsed; + + cmsUNUSED_PARAMETER(ContextID); +} + + + + +cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, + cmsPSResourceType Type, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* io) +{ + cmsUInt32Number rc; + + + switch (Type) { + + case cmsPS_RESOURCE_CSA: + rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io); + break; + + default: + case cmsPS_RESOURCE_CRD: + rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io); + break; + } + + return rc; +} + + + +cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number dwFlags, + void* Buffer, cmsUInt32Number dwBufferLen) +{ + cmsIOHANDLER* mem; + cmsUInt32Number dwBytesUsed; + + // Set up the serialization engine + if (Buffer == NULL) + mem = cmsOpenIOhandlerFromNULL(ContextID); + else + mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); + + if (!mem) return 0; + + dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem); + + // Get rid of memory stream + cmsCloseIOhandler(mem); + + return dwBytesUsed; +} + + + +// Does create a Color Space Array on XYZ colorspace for PostScript usage +cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + void* Buffer, + cmsUInt32Number dwBufferLen) +{ + cmsIOHANDLER* mem; + cmsUInt32Number dwBytesUsed; + + if (Buffer == NULL) + mem = cmsOpenIOhandlerFromNULL(ContextID); + else + mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); + + if (!mem) return 0; + + dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem); + + // Get rid of memory stream + cmsCloseIOhandler(mem); + + return dwBytesUsed; + +} diff --git a/thirdparty/liblcms2/src/cmssamp.c b/thirdparty/liblcms2/src/cmssamp.c new file mode 100644 index 00000000..090d96de --- /dev/null +++ b/thirdparty/liblcms2/src/cmssamp.c @@ -0,0 +1,266 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + + +// This file contains routines for resampling and LUT optimization, black point detection +// and black preservation. + +// Black point detection ------------------------------------------------------------------------- + + +// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs +static +cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent) +{ + cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); + cmsHTRANSFORM xform; + cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE }; + cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 }; + cmsHPROFILE hProfiles[4]; + cmsUInt32Number Intents[4]; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab; + Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC; + + xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents, + States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + + cmsCloseProfile(hLab); + return xform; +} + +// Use darker colorants to obtain black point. This works in the relative colorimetric intent and +// assumes more ink results in darker colors. No ink limit is assumed. +static +cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, + cmsUInt32Number Intent, + cmsCIEXYZ* BlackPoint, + cmsUInt32Number dwFlags) +{ + cmsUInt16Number *Black; + cmsHTRANSFORM xform; + cmsColorSpaceSignature Space; + cmsUInt32Number nChannels; + cmsUInt32Number dwFormat; + cmsHPROFILE hLab; + cmsCIELab Lab; + cmsCIEXYZ BlackXYZ; + cmsContext ContextID = cmsGetProfileContextID(hInput); + + // If the profile does not support input direction, assume Black point 0 + if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Create a formatter which has n channels and floating point + dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE); + + // Try to get black by using black colorant + Space = cmsGetColorSpace(hInput); + + // This function returns darker colorant in 16 bits for several spaces + if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + if (nChannels != T_CHANNELS(dwFormat)) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Lab will be used as the output space, but lab2 will avoid recursion + hLab = cmsCreateLab2ProfileTHR(ContextID, NULL); + if (hLab == NULL) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Create the transform + xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat, + hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); + cmsCloseProfile(hLab); + + if (xform == NULL) { + // Something went wrong. Get rid of open resources and return zero as black + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Convert black to Lab + cmsDoTransform(xform, Black, &Lab, 1); + + // Force it to be neutral, clip to max. L* of 50 + Lab.a = Lab.b = 0; + if (Lab.L > 50) Lab.L = 50; + + // Free the resources + cmsDeleteTransform(xform); + + // Convert from Lab (which is now clipped) to XYZ. + cmsLab2XYZ(NULL, &BlackXYZ, &Lab); + + if (BlackPoint != NULL) + *BlackPoint = BlackXYZ; + + return TRUE; + + cmsUNUSED_PARAMETER(dwFlags); +} + +// Get a black point of output CMYK profile, discounting any ink-limiting embedded +// in the profile. For doing that, we use perceptual intent in input direction: +// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab +static +cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) + +{ + cmsHTRANSFORM hRoundTrip; + cmsCIELab LabIn, LabOut; + cmsCIEXYZ BlackXYZ; + + // Is the intent supported by the profile? + if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return TRUE; + } + + hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL); + if (hRoundTrip == NULL) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + LabIn.L = LabIn.a = LabIn.b = 0; + cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1); + + // Clip Lab to reasonable limits + if (LabOut.L > 50) LabOut.L = 50; + LabOut.a = LabOut.b = 0; + + cmsDeleteTransform(hRoundTrip); + + // Convert it to XYZ + cmsLab2XYZ(NULL, &BlackXYZ, &LabOut); + + if (BlackPoint != NULL) + *BlackPoint = BlackXYZ; + + return TRUE; +} + +// This function shouldn't exist at all -- there is such quantity of broken +// profiles on black point tag, that we must somehow fix chromaticity to +// avoid huge tint when doing Black point compensation. This function does +// just that. There is a special flag for using black point tag, but turned +// off by default because it is bogus on most profiles. The detection algorithm +// involves to turn BP to neutral and to use only L component. + +cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + + // Zero for black point + if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. Black point tag is deprecated in V4. + + if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && + (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { + + // Matrix shaper share MRC & perceptual intents + if (cmsIsMatrixShaper(hProfile)) + return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); + + // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents + BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; + BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; + BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; + + return TRUE; + } + + +#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG + + // v2, v4 rel/abs colorimetric + if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) && + Intent == INTENT_RELATIVE_COLORIMETRIC) { + + cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite; + cmsCIELab Lab; + + // If black point is specified, then use it, + + BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag); + if (BlackPtr != NULL) { + + BlackXYZ = *BlackPtr; + _cmsReadMediaWhitePoint(&MediaWhite, hProfile); + + // Black point is absolute XYZ, so adapt to D50 to get PCS value + cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ); + + // Force a=b=0 to get rid of any chroma + cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint); + Lab.a = Lab.b = 0; + if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50 + cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab); + + if (BlackPoint != NULL) + *BlackPoint = TrustedBlackPoint; + + return TRUE; + } + } +#endif + + // That is about v2 profiles. + + // If output profile, discount ink-limiting and that's all + if (Intent == INTENT_RELATIVE_COLORIMETRIC && + (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) && + (cmsGetColorSpace(hProfile) == cmsSigCmykData)) + return BlackPointUsingPerceptualBlack(BlackPoint, hProfile); + + // Nope, compute BP using current intent. + return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags); +} + + diff --git a/thirdparty/liblcms2/src/cmssm.c b/thirdparty/liblcms2/src/cmssm.c new file mode 100644 index 00000000..e5a6b0d5 --- /dev/null +++ b/thirdparty/liblcms2/src/cmssm.c @@ -0,0 +1,734 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// ------------------------------------------------------------------------ + +// Gamut boundary description by using Jan Morovic's Segment maxima method +// Many thanks to Jan for allowing me to use his algorithm. + +// r = C* +// alpha = Hab +// theta = L* + +#define SECTORS 16 // number of divisions in alpha and theta + +// Spherical coordinates +typedef struct { + + cmsFloat64Number r; + cmsFloat64Number alpha; + cmsFloat64Number theta; + +} cmsSpherical; + +typedef enum { + GP_EMPTY, + GP_SPECIFIED, + GP_MODELED + + } GDBPointType; + + +typedef struct { + + GDBPointType Type; + cmsSpherical p; // Keep also alpha & theta of maximum + +} cmsGDBPoint; + + +typedef struct { + + cmsContext ContextID; + cmsGDBPoint Gamut[SECTORS][SECTORS]; + +} cmsGDB; + + +// A line using the parametric form +// P = a + t*u +typedef struct { + + cmsVEC3 a; + cmsVEC3 u; + +} cmsLine; + + +// A plane using the parametric form +// Q = b + r*v + s*w +typedef struct { + + cmsVEC3 b; + cmsVEC3 v; + cmsVEC3 w; + +} cmsPlane; + + + +// -------------------------------------------------------------------------------------------- + +// ATAN2() which always returns degree positive numbers + +static +cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x) +{ + cmsFloat64Number a; + + // Deal with undefined case + if (x == 0.0 && y == 0.0) return 0; + + a = (atan2(y, x) * 180.0) / M_PI; + + while (a < 0) { + a += 360; + } + + return a; +} + +// Convert to spherical coordinates +static +void ToSpherical(cmsSpherical* sp, const cmsVEC3* v) +{ + + cmsFloat64Number L, a, b; + + L = v ->n[VX]; + a = v ->n[VY]; + b = v ->n[VZ]; + + sp ->r = sqrt( L*L + a*a + b*b ); + + if (sp ->r == 0) { + sp ->alpha = sp ->theta = 0; + return; + } + + sp ->alpha = _cmsAtan2(a, b); + sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L); +} + + +// Convert to cartesian from spherical +static +void ToCartesian(cmsVEC3* v, const cmsSpherical* sp) +{ + cmsFloat64Number sin_alpha; + cmsFloat64Number cos_alpha; + cmsFloat64Number sin_theta; + cmsFloat64Number cos_theta; + cmsFloat64Number L, a, b; + + sin_alpha = sin((M_PI * sp ->alpha) / 180.0); + cos_alpha = cos((M_PI * sp ->alpha) / 180.0); + sin_theta = sin((M_PI * sp ->theta) / 180.0); + cos_theta = cos((M_PI * sp ->theta) / 180.0); + + a = sp ->r * sin_theta * sin_alpha; + b = sp ->r * sin_theta * cos_alpha; + L = sp ->r * cos_theta; + + v ->n[VX] = L; + v ->n[VY] = a; + v ->n[VZ] = b; +} + + +// Quantize sector of a spherical coordinate. Saturate 360, 180 to last sector +// The limits are the centers of each sector, so +static +void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta) +{ + *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) ); + *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) ); + + if (*alpha >= SECTORS) + *alpha = SECTORS-1; + if (*theta >= SECTORS) + *theta = SECTORS-1; +} + + +// Line determined by 2 points +static +void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b) +{ + + _cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]); + _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX], + b ->n[VY] - a ->n[VY], + b ->n[VZ] - a ->n[VZ]); +} + + +// Evaluate parametric line +static +void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t) +{ + p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX]; + p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY]; + p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ]; +} + + + +/* + Closest point in sector line1 to sector line2 (both are defined as 0 <=t <= 1) + http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm + + Copyright 2001, softSurfer (www.softsurfer.com) + This code may be freely used and modified for any purpose + providing that this copyright notice is included with it. + SoftSurfer makes no warranty for this code, and cannot be held + liable for any real or imagined damage resulting from its use. + Users of this code must verify correctness for their application. + +*/ + +static +cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2) +{ + cmsFloat64Number a, b, c, d, e, D; + cmsFloat64Number sc, sN, sD; + cmsFloat64Number tc, tN, tD; + cmsVEC3 w0; + + _cmsVEC3minus(&w0, &line1 ->a, &line2 ->a); + + a = _cmsVEC3dot(&line1 ->u, &line1 ->u); + b = _cmsVEC3dot(&line1 ->u, &line2 ->u); + c = _cmsVEC3dot(&line2 ->u, &line2 ->u); + d = _cmsVEC3dot(&line1 ->u, &w0); + e = _cmsVEC3dot(&line2 ->u, &w0); + + D = a*c - b * b; // Denominator + sD = tD = D; // default sD = D >= 0 + + if (D < MATRIX_DET_TOLERANCE) { // the lines are almost parallel + + sN = 0.0; // force using point P0 on segment S1 + sD = 1.0; // to prevent possible division by 0.0 later + tN = e; + tD = c; + } + else { // get the closest points on the infinite lines + + sN = (b*e - c*d); + tN = (a*e - b*d); + + if (sN < 0.0) { // sc < 0 => the s=0 edge is visible + + sN = 0.0; + tN = e; + tD = c; + } + else if (sN > sD) { // sc > 1 => the s=1 edge is visible + sN = sD; + tN = e + b; + tD = c; + } + } + + if (tN < 0.0) { // tc < 0 => the t=0 edge is visible + + tN = 0.0; + // recompute sc for this edge + if (-d < 0.0) + sN = 0.0; + else if (-d > a) + sN = sD; + else { + sN = -d; + sD = a; + } + } + else if (tN > tD) { // tc > 1 => the t=1 edge is visible + + tN = tD; + + // recompute sc for this edge + if ((-d + b) < 0.0) + sN = 0; + else if ((-d + b) > a) + sN = sD; + else { + sN = (-d + b); + sD = a; + } + } + // finally do the division to get sc and tc + sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD); + tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD); + + GetPointOfLine(r, line1, sc); + return TRUE; +} + + + +// ------------------------------------------------------------------ Wrapper + + +// Allocate & free structure +cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID) +{ + cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB)); + if (gbd == NULL) return NULL; + + gbd -> ContextID = ContextID; + + return (cmsHANDLE) gbd; +} + + +void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD) +{ + cmsGDB* gbd = (cmsGDB*) hGBD; + if (hGBD != NULL) + _cmsFree(gbd->ContextID, (void*) gbd); +} + + +// Auxiliar to retrieve a pointer to the segmentr containing the Lab value +static +cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) +{ + cmsVEC3 v; + int alpha, theta; + + // Housekeeping + _cmsAssert(gbd != NULL); + _cmsAssert(Lab != NULL); + _cmsAssert(sp != NULL); + + // Center L* by substracting half of its domain, that's 50 + _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b); + + // Convert to spherical coordinates + ToSpherical(sp, &v); + + if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) { + cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range"); + return NULL; + } + + // On which sector it falls? + QuantizeToSector(sp, &alpha, &theta); + + if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) { + cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range"); + return NULL; + } + + // Get pointer to the sector + return &gbd ->Gamut[theta][alpha]; +} + +// Add a point to gamut descriptor. Point to add is in Lab color space. +// GBD is centered on a=b=0 and L*=50 +cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) +{ + cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDBPoint* ptr; + cmsSpherical sp; + + + // Get pointer to the sector + ptr = GetPoint(gbd, Lab, &sp); + if (ptr == NULL) return FALSE; + + // If no samples at this sector, add it + if (ptr ->Type == GP_EMPTY) { + + ptr -> Type = GP_SPECIFIED; + ptr -> p = sp; + } + else { + + + // Substitute only if radius is greater + if (sp.r > ptr -> p.r) { + + ptr -> Type = GP_SPECIFIED; + ptr -> p = sp; + } + } + + return TRUE; +} + +// Check if a given point falls inside gamut +cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) +{ + cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDBPoint* ptr; + cmsSpherical sp; + + // Get pointer to the sector + ptr = GetPoint(gbd, Lab, &sp); + if (ptr == NULL) return FALSE; + + // If no samples at this sector, return no data + if (ptr ->Type == GP_EMPTY) return FALSE; + + // In gamut only if radius is greater + + return (sp.r <= ptr -> p.r); +} + +// ----------------------------------------------------------------------------------------------------------------------- + +// Find near sectors. The list of sectors found is returned on Close[]. +// The function returns the number of sectors as well. + +// 24 9 10 11 12 +// 23 8 1 2 13 +// 22 7 * 3 14 +// 21 6 5 4 15 +// 20 19 18 17 16 +// +// Those are the relative movements +// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, +// {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1}, +// {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0}, +// {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1}, +// {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}}; + + +static +const struct _spiral { + + int AdvX, AdvY; + + } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1}, + {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, + {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2}, + {-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} }; + +#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral)) + +static +int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) +{ + int nSectors = 0; + int i, a, t; + cmsGDBPoint* pt; + + for (i=0; i < NSTEPS; i++) { + + a = alpha + Spiral[i].AdvX; + t = theta + Spiral[i].AdvY; + + // Cycle at the end + a %= SECTORS; + t %= SECTORS; + + // Cycle at the begin + if (a < 0) a = SECTORS + a; + if (t < 0) t = SECTORS + t; + + pt = &gbd ->Gamut[t][a]; + + if (pt -> Type != GP_EMPTY) { + + Close[nSectors++] = pt; + } + } + + return nSectors; +} + + +// Interpolate a missing sector. Method identifies whatever this is top, bottom or mid +static +cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) +{ + cmsSpherical sp; + cmsVEC3 Lab; + cmsVEC3 Centre; + cmsLine ray; + int nCloseSectors; + cmsGDBPoint* Close[NSTEPS]; + cmsSpherical closel, templ; + cmsLine edge; + int k, m; + + // Is that point already specified? + if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE; + + // Fill close points + nCloseSectors = FindNearSectors(gbd, alpha, theta, Close); + + + // Find a central point on the sector + sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS); + sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS); + sp.r = 50.0; + + // Convert to Cartesian + ToCartesian(&Lab, &sp); + + // Create a ray line from centre to this point + _cmsVEC3init(&Centre, 50.0, 0, 0); + LineOf2Points(&ray, &Lab, &Centre); + + // For all close sectors + closel.r = 0.0; + closel.alpha = 0; + closel.theta = 0; + + for (k=0; k < nCloseSectors; k++) { + + for(m = k+1; m < nCloseSectors; m++) { + + cmsVEC3 temp, a1, a2; + + // A line from sector to sector + ToCartesian(&a1, &Close[k]->p); + ToCartesian(&a2, &Close[m]->p); + + LineOf2Points(&edge, &a1, &a2); + + // Find a line + ClosestLineToLine(&temp, &ray, &edge); + + // Convert to spherical + ToSpherical(&templ, &temp); + + + if ( templ.r > closel.r && + templ.theta >= (theta*180.0/SECTORS) && + templ.theta <= ((theta+1)*180.0/SECTORS) && + templ.alpha >= (alpha*360.0/SECTORS) && + templ.alpha <= ((alpha+1)*360.0/SECTORS)) { + + closel = templ; + } + } + } + + gbd ->Gamut[theta][alpha].p = closel; + gbd ->Gamut[theta][alpha].Type = GP_MODELED; + + return TRUE; + +} + + +// Interpolate missing parts. The algorithm fist computes slices at +// theta=0 and theta=Max. +cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) +{ + int alpha, theta; + cmsGDB* gbd = (cmsGDB*) hGBD; + + _cmsAssert(hGBD != NULL); + + // Interpolate black + for (alpha = 0; alpha <= SECTORS; alpha++) { + + if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE; + } + + // Interpolate white + for (alpha = 0; alpha <= SECTORS; alpha++) { + + if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE; + } + + + // Interpolate Mid + for (theta = 1; theta < SECTORS; theta++) { + for (alpha = 0; alpha <= SECTORS; alpha++) { + + if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE; + } + } + + // Done + return TRUE; + + cmsUNUSED_PARAMETER(dwFlags); +} + + + + +// -------------------------------------------------------------------------------------------------------- + +// Great for debug, but not suitable for real use + +#if 0 +cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) +{ + FILE* fp; + int i, j; + cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDBPoint* pt; + + fp = fopen (fname, "wt"); + if (fp == NULL) + return FALSE; + + fprintf (fp, "#VRML V2.0 utf8\n"); + + // set the viewing orientation and distance + fprintf (fp, "DEF CamTest Group {\n"); + fprintf (fp, "\tchildren [\n"); + fprintf (fp, "\t\tDEF Cameras Group {\n"); + fprintf (fp, "\t\t\tchildren [\n"); + fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n"); + fprintf (fp, "\t\t\t\t\tposition 0 0 340\n"); + fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n"); + fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t]\n"); + fprintf (fp, "\t\t},\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); + + // Output the background stuff + fprintf (fp, "Background {\n"); + fprintf (fp, "\tskyColor [\n"); + fprintf (fp, "\t\t.5 .5 .5\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); + + // Output the shape stuff + fprintf (fp, "Transform {\n"); + fprintf (fp, "\tscale .3 .3 .3\n"); + fprintf (fp, "\tchildren [\n"); + + // Draw the axes as a shape: + fprintf (fp, "\t\tShape {\n"); + fprintf (fp, "\t\t\tappearance Appearance {\n"); + fprintf (fp, "\t\t\t\tmaterial Material {\n"); + fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n"); + fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n"); + fprintf (fp, "\t\t\t\t\tshininess 0.8\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n"); + fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); + fprintf (fp, "\t\t\t\t\tpoint [\n"); + fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n"); + fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0); + fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0); + fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t\tcoordIndex [\n"); + fprintf (fp, "\t\t\t\t\t0, 1, -1\n"); + fprintf (fp, "\t\t\t\t\t0, 2, -1\n"); + fprintf (fp, "\t\t\t\t\t0, 3, -1]\n"); + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t}\n"); + + + fprintf (fp, "\t\tShape {\n"); + fprintf (fp, "\t\t\tappearance Appearance {\n"); + fprintf (fp, "\t\t\t\tmaterial Material {\n"); + fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n"); + fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n"); + fprintf (fp, "\t\t\t\t\tshininess 0.8\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t\tgeometry PointSet {\n"); + + // fill in the points here + fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); + fprintf (fp, "\t\t\t\t\tpoint [\n"); + + // We need to transverse all gamut hull. + for (i=0; i < SECTORS; i++) + for (j=0; j < SECTORS; j++) { + + cmsVEC3 v; + + pt = &gbd ->Gamut[i][j]; + ToCartesian(&v, &pt ->p); + + fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]); + + if ((j == SECTORS - 1) && (i == SECTORS - 1)) + fprintf (fp, "]\n"); + else + fprintf (fp, ",\n"); + + } + + fprintf (fp, "\t\t\t\t}\n"); + + + + // fill in the face colors + fprintf (fp, "\t\t\t\tcolor Color {\n"); + fprintf (fp, "\t\t\t\t\tcolor [\n"); + + for (i=0; i < SECTORS; i++) + for (j=0; j < SECTORS; j++) { + + cmsVEC3 v; + + pt = &gbd ->Gamut[i][j]; + + + ToCartesian(&v, &pt ->p); + + + if (pt ->Type == GP_EMPTY) + fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0); + else + if (pt ->Type == GP_MODELED) + fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5); + else { + fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0); + + } + + if ((j == SECTORS - 1) && (i == SECTORS - 1)) + fprintf (fp, "]\n"); + else + fprintf (fp, ",\n"); + } + fprintf (fp, "\t\t\t}\n"); + + + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t}\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); + + fclose (fp); + + return TRUE; +} +#endif + diff --git a/thirdparty/liblcms2/src/cmstypes.c b/thirdparty/liblcms2/src/cmstypes.c new file mode 100644 index 00000000..28f06d5d --- /dev/null +++ b/thirdparty/liblcms2/src/cmstypes.c @@ -0,0 +1,4955 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Tag Serialization ----------------------------------------------------------------------------- +// This file implements every single tag and tag type as described in the ICC spec. Some types +// have been deprecated, like ncl and Data. There is no implementation for those types as there +// are no profiles holding them. The programmer can also extend this list by defining his own types +// by using the appropiate plug-in. There are three types of plug ins regarding that. First type +// allows to define new tags using any existing type. Next plug-in type allows to define new types +// and the third one is very specific: allows to extend the number of elements in the multiprofile +// elements special type. +//-------------------------------------------------------------------------------------------------- + +// Some broken types +#define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8) +#define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00) + +// This is the linked list that keeps track of the defined types +typedef struct _cmsTagTypeLinkedList_st { + + cmsTagTypeHandler Handler; + struct _cmsTagTypeLinkedList_st* Next; + +} _cmsTagTypeLinkedList; + +// Some macros to define callbacks. +#define READ_FN(x) Type_##x##_Read +#define WRITE_FN(x) Type_##x##_Write +#define FREE_FN(x) Type_##x##_Free +#define DUP_FN(x) Type_##x##_Dup + +// Helper macro to define a handler. Callbacks do have a fixed naming convention. +#define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x) } + +// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention +#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree } + +// Register a new type handler. This routine is shared between normal types and MPE +static +cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) +{ + cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; + _cmsTagTypeLinkedList *pt, *Anterior = NULL; + + // Calling the function with NULL as plug-in would unregister the plug in. + if (Data == NULL) { + + LinkedList[DefaultListCount-1].Next = NULL; + return TRUE; + } + + pt = Anterior = LinkedList; + while (pt != NULL) { + + if (Plugin->Handler.Signature == pt -> Handler.Signature) { + pt ->Handler = Plugin ->Handler; // Replace old behaviour. + // Note that since no memory is allocated, unregister does not + // reset this action. + return TRUE; + } + + Anterior = pt; + pt = pt ->Next; + } + + // Registering happens in plug-in memory pool + pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagTypeLinkedList)); + if (pt == NULL) return FALSE; + + pt ->Handler = Plugin ->Handler; + pt ->Next = NULL; + + if (Anterior) + Anterior -> Next = pt; + + return TRUE; +} + +// Return handler for a given type or NULL if not found. Shared between normal types and MPE +static +cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList) +{ + _cmsTagTypeLinkedList* pt; + + for (pt = LinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + return NULL; +} + + +// Auxiliar to convert UTF-32 to UTF-16 in some cases +static +cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array) +{ + cmsUInt32Number i; + + _cmsAssert(io != NULL); + _cmsAssert(Array != NULL); + + for (i=0; i < n; i++) { + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE; + } + + return TRUE; +} + +static +cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) +{ + cmsUInt32Number i; + cmsUInt16Number tmp; + + _cmsAssert(io != NULL); + + for (i=0; i < n; i++) { + + if (Array != NULL) { + + if (!_cmsReadUInt16Number(io, &tmp)) return FALSE; + Array[i] = (wchar_t) tmp; + } + else { + if (!_cmsReadUInt16Number(io, NULL)) return FALSE; + } + + } + return TRUE; +} + +// To deal with position tables +typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag); + +// Helper function to deal with position tables as decribed in several addendums to ICC spec 4.2 +// A table of n elements is written, where first comes n records containing offsets and sizes and +// then a block containing the data itself. This allows to reuse same data in more than one entry +static +cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number Count, + cmsUInt32Number BaseOffset, + void *Cargo, + PositionTableEntryFn ElementFn) +{ + cmsUInt32Number i; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; + + // Let's take the offsets to each element + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + if (ElementOffsets == NULL) goto Error; + + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + if (ElementSizes == NULL) goto Error; + + for (i=0; i < Count; i++) { + + if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error; + if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error; + + ElementOffsets[i] += BaseOffset; + } + + // Seek to each element and read it + for (i=0; i < Count; i++) { + + if (!io -> Seek(io, ElementOffsets[i])) goto Error; + + // This is the reader callback + if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error; + } + + // Success + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return TRUE; + +Error: + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return FALSE; +} + +// Same as anterior, but for write position tables +static +cmsBool WritePositionTable(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number SizeOfTag, + cmsUInt32Number Count, + cmsUInt32Number BaseOffset, + void *Cargo, + PositionTableEntryFn ElementFn) +{ + cmsUInt32Number i; + cmsUInt32Number DirectoryPos, CurrentPos, Before; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; + + // Create table + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + if (ElementOffsets == NULL) goto Error; + + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + if (ElementSizes == NULL) goto Error; + + // Keep starting position of curve offsets + DirectoryPos = io ->Tell(io); + + // Write a fake directory to be filled latter on + for (i=0; i < Count; i++) { + + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size + } + + // Write each element. Keep track of the size as well. + for (i=0; i < Count; i++) { + + Before = io ->Tell(io); + ElementOffsets[i] = Before - BaseOffset; + + // Callback to write... + if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error; + + // Now the size + ElementSizes[i] = io ->Tell(io) - Before; + } + + // Write the directory + CurrentPos = io ->Tell(io); + if (!io ->Seek(io, DirectoryPos)) goto Error; + + for (i=0; i < Count; i++) { + if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; + } + + if (!io ->Seek(io, CurrentPos)) goto Error; + + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return TRUE; + +Error: + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return FALSE; +} + + +// ******************************************************************************** +// Type XYZ. Only one value is allowed +// ******************************************************************************** + +//The XYZType contains an array of three encoded values for the XYZ tristimulus +//values. Tristimulus values must be non-negative. The signed encoding allows for +//implementation optimizations by minimizing the number of fixed formats. + + +static +void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsCIEXYZ* xyz; + + *nItems = 0; + xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ)); + if (xyz == NULL) return NULL; + + if (!_cmsReadXYZNumber(io, xyz)) { + _cmsFree(self ->ContextID, xyz); + return NULL; + } + + *nItems = 1; + return (void*) xyz; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +static +cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data) +{ + return cmsSigXYZType; + + cmsUNUSED_PARAMETER(ICCVersion); + cmsUNUSED_PARAMETER(Data); +} + + +// ******************************************************************************** +// Type chromaticity. Only one value is allowed +// ******************************************************************************** +// The chromaticity tag type provides basic chromaticity data and type of +// phosphors or colorants of a monitor to applications and utilities. + +static +void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsCIExyYTRIPLE* chrm; + cmsUInt16Number nChans, Table; + + *nItems = 0; + chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE)); + if (chrm == NULL) return NULL; + + if (!_cmsReadUInt16Number(io, &nChans)) goto Error; + + // Let's recover from a bug introduced in early versions of lcms1 + if (nChans == 0 && SizeOfTag == 32) { + + if (!_cmsReadUInt16Number(io, NULL)) goto Error; + if (!_cmsReadUInt16Number(io, &nChans)) goto Error; + } + + if (nChans != 3) goto Error; + + if (!_cmsReadUInt16Number(io, &Table)) goto Error; + + if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error; + if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error; + + chrm ->Red.Y = 1.0; + + if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error; + if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error; + + chrm ->Green.Y = 1.0; + + if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error; + if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error; + + chrm ->Blue.Y = 1.0; + + *nItems = 1; + return (void*) chrm; + +Error: + _cmsFree(self ->ContextID, (void*) chrm); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io) +{ + if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE; + if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE; + + return TRUE; +} + +static +cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr; + + if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table + + if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE; + if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE; + if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE)); + cmsUNUSED_PARAMETER(n); +} + +static +void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigColorantOrderType +// ******************************************************************************** + +// This is an optional tag which specifies the laydown order in which colorants will +// be printed on an n-colorant device. The laydown order may be the same as the +// channel generation order listed in the colorantTableTag or the channel order of a +// colour space such as CMYK, in which case this tag is not needed. When this is not +// the case (for example, ink-towers sometimes use the order KCMY), this tag may be +// used to specify the laydown order of the colorants. + + +static +void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number* ColorantOrder; + cmsUInt32Number Count; + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + if (Count > cmsMAXCHANNELS) return NULL; + + ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number)); + if (ColorantOrder == NULL) return NULL; + + // We use FF as end marker + memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number)); + + if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) { + + _cmsFree(self ->ContextID, (void*) ColorantOrder); + return NULL; + } + + *nItems = 1; + return (void*) ColorantOrder; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr; + cmsUInt32Number i, sz, Count; + + // Get the length + for (Count=i=0; i < cmsMAXCHANNELS; i++) { + if (ColorantOrder[i] != 0xFF) Count++; + } + + if (!_cmsWriteUInt32Number(io, Count)) return FALSE; + + sz = Count * sizeof(cmsUInt8Number); + if (!io -> Write(io, sz, ColorantOrder)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number)); + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigS15Fixed16ArrayType +// ******************************************************************************** +// This type represents an array of generic 4-byte/32-bit fixed point quantity. +// The number of values is determined from the size of the tag. + +static +void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsFloat64Number* array_double; + cmsUInt32Number i, n; + + *nItems = 0; + n = SizeOfTag / sizeof(cmsUInt32Number); + array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number)); + if (array_double == NULL) return NULL; + + for (i=0; i < n; i++) { + + if (!_cmsRead15Fixed16Number(io, &array_double[i])) { + + _cmsFree(self ->ContextID, array_double); + return NULL; + } + } + + *nItems = n; + return (void*) array_double; +} + +static +cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsFloat64Number* Value = (cmsFloat64Number*) Ptr; + cmsUInt32Number i; + + for (i=0; i < nItems; i++) { + + if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number)); +} + + +static +void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigU16Fixed16ArrayType +// ******************************************************************************** +// This type represents an array of generic 4-byte/32-bit quantity. +// The number of values is determined from the size of the tag. + + +static +void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsFloat64Number* array_double; + cmsUInt32Number v; + cmsUInt32Number i, n; + + *nItems = 0; + n = SizeOfTag / sizeof(cmsUInt32Number); + array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number)); + if (array_double == NULL) return NULL; + + for (i=0; i < n; i++) { + + if (!_cmsReadUInt32Number(io, &v)) { + _cmsFree(self ->ContextID, (void*) array_double); + return NULL; + } + + // Convert to cmsFloat64Number + array_double[i] = (cmsFloat64Number) (v / 65536.0); + } + + *nItems = n; + return (void*) array_double; +} + +static +cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsFloat64Number* Value = (cmsFloat64Number*) Ptr; + cmsUInt32Number i; + + for (i=0; i < nItems; i++) { + + cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5); + + if (!_cmsWriteUInt32Number(io, v)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number)); +} + +static +void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigSignatureType +// ******************************************************************************** +// +// The signatureType contains a four-byte sequence, Sequences of less than four +// characters are padded at the end with spaces, 20h. +// Typically this type is used for registered tags that can be displayed on many +// development systems as a sequence of four characters. + +static +void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature)); + if (SigPtr == NULL) return NULL; + + if (!_cmsReadUInt32Number(io, SigPtr)) return NULL; + *nItems = 1; + + return SigPtr; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsSignature* SigPtr = (cmsSignature*) Ptr; + + return _cmsWriteUInt32Number(io, *SigPtr); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature)); +} + +static +void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigTextType +// ******************************************************************************** +// +// The textType is a simple text structure that contains a 7-bit ASCII text string. +// The length of the string is obtained by subtracting 8 from the element size portion +// of the tag itself. This string must be terminated with a 00h byte. + +static +void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + char* Text = NULL; + cmsMLU* mlu = NULL; + + // Create a container + mlu = cmsMLUalloc(self ->ContextID, 1); + if (mlu == NULL) return NULL; + + *nItems = 0; + + // We need to store the "\0" at the end, so +1 + if (SizeOfTag == UINT_MAX) goto Error; + + Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); + if (Text == NULL) goto Error; + + if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error; + + // Make sure text is properly ended + Text[SizeOfTag] = 0; + *nItems = 1; + + // Keep the result + if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; + + _cmsFree(self ->ContextID, Text); + return (void*) mlu; + +Error: + if (mlu != NULL) + cmsMLUfree(mlu); + if (Text != NULL) + _cmsFree(self ->ContextID, Text); + + return NULL; +} + +// The conversion implies to choose a language. So, we choose the actual language. +static +cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + cmsUInt32Number size; + cmsBool rc; + char* Text; + + // Get the size of the string. Note there is an extra "\0" at the end + size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); + if (size == 0) return FALSE; // Cannot be zero! + + // Create memory + Text = (char*) _cmsMalloc(self ->ContextID, size); + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); + + // Write it, including separator + rc = io ->Write(io, size, Text); + + _cmsFree(self ->ContextID, Text); + return rc; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + cmsMLUfree(mlu); + return; + + cmsUNUSED_PARAMETER(self); +} + +static +cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data) +{ + if (ICCVersion >= 4.0) + return cmsSigMultiLocalizedUnicodeType; + + return cmsSigTextType; + + cmsUNUSED_PARAMETER(Data); +} + + +// ******************************************************************************** +// Type cmsSigDataType +// ******************************************************************************** + +// General purpose data type +static +void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsICCData* BinData; + cmsUInt32Number LenOfData; + + *nItems = 0; + + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + + LenOfData = SizeOfTag - sizeof(cmsUInt32Number); + if (LenOfData > INT_MAX) return NULL; + + BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1); + if (BinData == NULL) return NULL; + + BinData ->len = LenOfData; + if (!_cmsReadUInt32Number(io, &BinData->flag)) { + _cmsFree(self ->ContextID, BinData); + return NULL; + } + + if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) { + + _cmsFree(self ->ContextID, BinData); + return NULL; + } + + *nItems = 1; + + return (void*) BinData; +} + + +static +cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsICCData* BinData = (cmsICCData*) Ptr; + + if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE; + + return io ->Write(io, BinData ->len, BinData ->data); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + cmsICCData* BinData = (cmsICCData*) Ptr; + + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigTextDescriptionType +// ******************************************************************************** + +static +void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + char* Text = NULL; + cmsMLU* mlu = NULL; + cmsUInt32Number AsciiCount; + cmsUInt32Number i, UnicodeCode, UnicodeCount; + cmsUInt16Number ScriptCodeCode, Dummy; + cmsUInt8Number ScriptCodeCount; + + *nItems = 0; + + // One dword should be there + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + + // Read len of ASCII + if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Check for size + if (SizeOfTag < AsciiCount) return NULL; + + // All seems Ok, allocate the container + mlu = cmsMLUalloc(self ->ContextID, 1); + if (mlu == NULL) return NULL; + + // As many memory as size of tag + Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1); + if (Text == NULL) goto Error; + + // Read it + if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error; + SizeOfTag -= AsciiCount; + + // Make sure there is a terminator + Text[AsciiCount] = 0; + + // Set the MLU entry. From here we can be tolerant to wrong types + if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; + _cmsFree(self ->ContextID, (void*) Text); + Text = NULL; + + // Skip Unicode code + if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done; + if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done; + if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; + SizeOfTag -= 2* sizeof(cmsUInt32Number); + + if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; + + for (i=0; i < UnicodeCount; i++) { + if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done; + } + SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number); + + // Skip ScriptCode code if present. Some buggy profiles does have less + // data that stricttly required. We need to skip it as this type may come + // embedded in other types. + + if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) { + + if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done; + if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done; + + // Skip rest of tag + for (i=0; i < 67; i++) { + if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error; + } + } + +Done: + + *nItems = 1; + return mlu; + +Error: + if (Text) _cmsFree(self ->ContextID, (void*) Text); + if (mlu) cmsMLUfree(mlu); + return NULL; +} + + +// This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it +static +cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + char *Text = NULL; + wchar_t *Wide = NULL; + cmsUInt32Number len, len_aligned, len_filler_alignment; + cmsBool rc = FALSE; + char Filler[68]; + + // Used below for writting zeroes + memset(Filler, 0, sizeof(Filler)); + + // Get the len of string + len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); + + // From ICC3.4: It has been found that textDescriptionType can contain misaligned data + //(see clause 4.1 for the definition of “aligned”). Because the Unicode language + // code and Unicode count immediately follow the ASCII description, their + // alignment is not correct if the ASCII count is not a multiple of four. The + // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and + // writing software must be written carefully in order to handle these alignment + // problems. + + // Compute an aligned size + len_aligned = _cmsALIGNLONG(len); + len_filler_alignment = len_aligned - len; + + // Null strings + if (len <= 0) { + + Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char)); + Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t)); + } + else { + // Create independent buffers + Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char)); + if (Text == NULL) goto Error; + + Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t)); + if (Wide == NULL) goto Error; + + // Get both representations. + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char)); + cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); + } + + // * cmsUInt32Number count; * Description length + // * cmsInt8Number desc[count] * NULL terminated ascii string + // * cmsUInt32Number ucLangCode; * UniCode language code + // * cmsUInt32Number ucCount; * UniCode description length + // * cmsInt16Number ucDesc[ucCount];* The UniCode description + // * cmsUInt16Number scCode; * ScriptCode code + // * cmsUInt8Number scCount; * ScriptCode count + // * cmsInt8Number scDesc[67]; * ScriptCode Description + + if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error; + if (!io ->Write(io, len, Text)) goto Error; + if (!io ->Write(io, len_filler_alignment, Filler)) goto Error; + + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode + + // This part is tricky: we need an aligned tag size, and the ScriptCode part + // takes 70 bytes, so we need 2 extra bytes to do the alignment + + if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error; + + // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t) + if (!_cmsWriteWCharArray(io, len, Wide)) goto Error; + if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error; + + // ScriptCode Code & count (unused) + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + if (!_cmsWriteUInt8Number(io, 0)) goto Error; + + if (!io ->Write(io, 67, Filler)) goto Error; + + rc = TRUE; + +Error: + if (Text) _cmsFree(self ->ContextID, Text); + if (Wide) _cmsFree(self ->ContextID, Wide); + + return rc; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + + cmsMLUfree(mlu); + return; + + cmsUNUSED_PARAMETER(self); +} + + +static +cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data) +{ + if (ICCVersion >= 4.0) + return cmsSigMultiLocalizedUnicodeType; + + return cmsSigTextDescriptionType; + + cmsUNUSED_PARAMETER(Data); +} + + +// ******************************************************************************** +// Type cmsSigCurveType +// ******************************************************************************** + +static +void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number Count; + cmsToneCurve* NewGamma; + cmsUInt16Number Linear[2] = { 0, 0xffff }; + + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + switch (Count) { + + case 0: // Linear. + + NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, 2, Linear); + if (!NewGamma) return NULL; + *nItems = 1; + return NewGamma; + + case 1: // Specified as the exponent of gamma function + { + cmsUInt16Number SingleGammaFixed; + cmsFloat64Number SingleGamma; + + if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL; + SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed); + + *nItems = 1; + return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); + } + + default: // Curve + + NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL); + if (!NewGamma) return NULL; + + if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL; + + *nItems = 1; + return NewGamma; + } + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsToneCurve* Curve = (cmsToneCurve*) Ptr; + + if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) { + + // Single gamma, preserve number + cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]); + + if (!_cmsWriteUInt32Number(io, 1)) return FALSE; + if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE; + return TRUE; + + } + + if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE; + return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsToneCurve* gamma = (cmsToneCurve*) Ptr; + + cmsFreeToneCurve(gamma); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigParametricCurveType +// ******************************************************************************** + + +// Decide which curve type to use on writting +static +cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data) +{ + cmsToneCurve* Curve = (cmsToneCurve*) Data; + + if (ICCVersion < 4.0) return cmsSigCurveType; + if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric + if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves + + return cmsSigParametricCurveType; +} + +static +void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + static const int ParamsByType[] = { 1, 3, 4, 5, 7 }; + cmsFloat64Number Params[10]; + cmsUInt16Number Type; + int i, n; + cmsToneCurve* NewGamma; + + if (!_cmsReadUInt16Number(io, &Type)) return NULL; + if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved + + if (Type > 4) { + + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type); + return NULL; + } + + memset(Params, 0, sizeof(Params)); + n = ParamsByType[Type]; + + for (i=0; i < n; i++) { + + if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL; + } + + NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params); + + *nItems = 1; + return NewGamma; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsToneCurve* Curve = (cmsToneCurve*) Ptr; + int i, nParams; + static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 }; + + + if (Curve ->nSegments > 1 || Curve -> Segments[0].Type < 1) { + + cmsSignalError(self->ContextID, 0, "Multisegment or Inverted parametric curves cannot be written"); + return FALSE; + } + + nParams = ParamsByType[Curve ->Segments[0].Type]; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE; + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved + + for (i=0; i < nParams; i++) { + + if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsToneCurve* gamma = (cmsToneCurve*) Ptr; + + cmsFreeToneCurve(gamma); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigDateTimeType +// ******************************************************************************** + +// A 12-byte value representation of the time and date, where the byte usage is assigned +// as specified in table 1. The actual values are encoded as 16-bit unsigned integers +// (uInt16Number - see 5.1.6). +// +// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time +// (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local +// time to UTC when setting these values. Programmes that display these values may show +// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or +// display both UTC and local versions of the dateTimeNumber. + +static +void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsDateTimeNumber timestamp; + struct tm * NewDateTime; + + *nItems = 0; + NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm)); + if (NewDateTime == NULL) return NULL; + + if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL; + + _cmsDecodeDateTimeNumber(×tamp, NewDateTime); + + *nItems = 1; + return NewDateTime; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + struct tm * DateTime = (struct tm*) Ptr; + cmsDateTimeNumber timestamp; + + _cmsEncodeDateTimeNumber(×tamp, DateTime); + if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + + +// ******************************************************************************** +// Type icMeasurementType +// ******************************************************************************** + +/* +The measurementType information refers only to the internal profile data and is +meant to provide profile makers an alternative to the default measurement +specifications. +*/ + +static +void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsICCMeasurementConditions mc; + + if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL; + if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL; + if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL; + if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL; + if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL; + + *nItems = 1; + return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions)); + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr; + + if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE; + if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE; + if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE; + if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigMultiLocalizedUnicodeType +// ******************************************************************************** +// +// Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from +// Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be +// taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance) +// + +static +void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsMLU* mlu; + cmsUInt32Number Count, RecLen, NumOfWchar; + cmsUInt32Number SizeOfHeader; + cmsUInt32Number Len, Offset; + cmsUInt32Number i; + wchar_t* Block; + cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition; + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + if (!_cmsReadUInt32Number(io, &RecLen)) return NULL; + + if (RecLen != 12) { + + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported."); + return NULL; + } + + mlu = cmsMLUalloc(self ->ContextID, Count); + if (mlu == NULL) return NULL; + + mlu ->UsedEntries = Count; + + SizeOfHeader = 12 * Count + sizeof(_cmsTagBase); + LargestPosition = 0; + + for (i=0; i < Count; i++) { + + if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error; + if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error; + + // Now deal with Len and offset. + if (!_cmsReadUInt32Number(io, &Len)) goto Error; + if (!_cmsReadUInt32Number(io, &Offset)) goto Error; + + // Check for overflow + if (Offset < (SizeOfHeader + 8)) goto Error; + + // True begin of the string + BeginOfThisString = Offset - SizeOfHeader - 8; + + // Ajust to wchar_t elements + mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + + // To guess maximum size, add offset + len + EndOfThisString = BeginOfThisString + Len; + if (EndOfThisString > LargestPosition) + LargestPosition = EndOfThisString; + } + + // Now read the remaining of tag and fill all strings. Substract the directory + SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + + Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); + if (Block == NULL) goto Error; + + NumOfWchar = SizeOfTag / sizeof(wchar_t); + + if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error; + + mlu ->MemPool = Block; + mlu ->PoolSize = SizeOfTag; + mlu ->PoolUsed = SizeOfTag; + + *nItems = 1; + return (void*) mlu; + +Error: + if (mlu) cmsMLUfree(mlu); + return NULL; +} + +static +cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMLU* mlu =(cmsMLU*) Ptr; + cmsUInt32Number HeaderSize; + cmsUInt32Number Len, Offset; + int i; + + if (Ptr == NULL) { + + // Empty placeholder + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 12)) return FALSE; + return TRUE; + } + + if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE; + if (!_cmsWriteUInt32Number(io, 12)) return FALSE; + + HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase); + + for (i=0; i < mlu ->UsedEntries; i++) { + + Len = mlu ->Entries[i].Len; + Offset = mlu ->Entries[i].StrW; + + Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t); + Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8; + + if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE; + if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE; + if (!_cmsWriteUInt32Number(io, Len)) return FALSE; + if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; + } + + if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMLUfree((cmsMLU*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigLut8Type +// ******************************************************************************** + +// Decide which LUT type to use on writting +static +cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data) +{ + cmsPipeline* Lut = (cmsPipeline*) Data; + + if (ICCVersion < 4.0) { + if (Lut ->SaveAs8Bits) return cmsSigLut8Type; + return cmsSigLut16Type; + } + else { + return cmsSigLutAtoBType; + } +} + +static +cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data) +{ + cmsPipeline* Lut = (cmsPipeline*) Data; + + if (ICCVersion < 4.0) { + if (Lut ->SaveAs8Bits) return cmsSigLut8Type; + return cmsSigLut16Type; + } + else { + return cmsSigLutBtoAType; + } +} + +/* +This structure represents a colour transform using tables of 8-bit precision. +This type contains four processing elements: a 3 by 3 matrix (which shall be +the identity matrix unless the input colour space is XYZ), a set of one dimensional +input tables, a multidimensional lookup table, and a set of one dimensional output +tables. Data is processed using these elements via the following sequence: +(matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables) + +Byte Position Field Length (bytes) Content Encoded as... +8 1 Number of Input Channels (i) uInt8Number +9 1 Number of Output Channels (o) uInt8Number +10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number +11 1 Reserved for padding (fill with 00h) + +12..15 4 Encoded e00 parameter s15Fixed16Number +*/ + + +// Read 8 bit tables as gamma functions +static +cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels) +{ + cmsStage* mpe; + cmsUInt8Number* Temp = NULL; + int i, j; + cmsToneCurve* Tables[cmsMAXCHANNELS]; + + if (nChannels > cmsMAXCHANNELS) return FALSE; + + memset(Tables, 0, sizeof(Tables)); + + Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256); + if (Temp == NULL) return FALSE; + + for (i=0; i < nChannels; i++) { + Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); + if (Tables[i] == NULL) goto Error; + } + + for (i=0; i < nChannels; i++) { + + if (io ->Read(io, Temp, 256, 1) != 1) goto Error; + + for (j=0; j < 256; j++) + Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]); + } + + _cmsFree(ContextID, Temp); + + + mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); + if (mpe == NULL) goto Error; + + cmsPipelineInsertStage(lut, cmsAT_END, mpe); + + for (i=0; i < nChannels; i++) + cmsFreeToneCurve(Tables[i]); + + return TRUE; + +Error: + for (i=0; i < nChannels; i++) { + if (Tables[i]) cmsFreeToneCurve(Tables[i]); + } + + if (Temp) _cmsFree(ContextID, Temp); + return FALSE; +} + + +static +cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables) +{ + int j; + cmsUInt32Number i; + cmsUInt8Number val; + + for (i=0; i < n; i++) { + + if (Tables) { + + if (Tables ->TheCurves[i]->nEntries != 256) { + cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); + return FALSE; + } + + } + + for (j=0; j < 256; j++) { + + if (Tables != NULL) + val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); + else + val = (cmsUInt8Number) j; + + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } + } + return TRUE; +} + + +// Check overflow +static +unsigned int uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) +{ + cmsUInt32Number rv = 1, rc; + + if (a == 0) return 0; + if (n == 0) return 0; + + for (; b > 0; b--) { + + rv *= a; + + // Check for overflow + if (rv > UINT_MAX / a) return 0; + + } + + rc = rv * n; + + if (rv != rc / n) return 0; + return rc; +} + + +// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. +// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust +// PCS on BToAxx tags and AtoB if abstract. We need to fix input direction. + +static +void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; + cmsUInt8Number* Temp = NULL; + cmsPipeline* NewLUT = NULL; + cmsStage *mpemat, *mpeclut; + cmsUInt32Number nTabSize, i; + cmsFloat64Number Matrix[3*3]; + + *nItems = 0; + + if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error; + if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error; + if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error; + + // Padding + if (!_cmsReadUInt8Number(io, NULL)) goto Error; + + // Do some checking + + if (InputChannels > cmsMAXCHANNELS) goto Error; + if (OutputChannels > cmsMAXCHANNELS) goto Error; + + // Allocates an empty Pipeline + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); + if (NewLUT == NULL) goto Error; + + // Read the Matrix + if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; + + + // Only operates if not identity... + if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { + + mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); + if (mpemat == NULL) goto Error; + cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, mpemat); + } + + // Get input tables + if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error; + + // Get 3D CLUT. Check the overflow.... + nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize > 0) { + + cmsUInt16Number *PtrW, *T; + cmsUInt32Number Tsize; + + Tsize = (cmsUInt32Number) nTabSize * sizeof(cmsUInt16Number); + + PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); + if (T == NULL) goto Error; + + Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); + if (Temp == NULL) goto Error; + + if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error; + + for (i = 0; i < nTabSize; i++) { + + *PtrW++ = FROM_8_TO_16(Temp[i]); + } + _cmsFree(self ->ContextID, Temp); + Temp = NULL; + + + mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); + if (mpeclut == NULL) goto Error; + cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); + _cmsFree(self ->ContextID, T); + } + + + // Get output tables + if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error; + + *nItems = 1; + return NewLUT; + +Error: + if (NewLUT != NULL) cmsPipelineFree(NewLUT); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin. +static +cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number j, nTabSize; + cmsUInt8Number val; + cmsPipeline* NewLUT = (cmsPipeline*) Ptr; + cmsStage* mpe; + _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; + _cmsStageMatrixData* MatMPE = NULL; + _cmsStageCLutData* clut = NULL; + int clutPoints; + + // Disassemble the LUT into components. + mpe = NewLUT -> Elements; + if (mpe ->Type == cmsSigMatrixElemType) { + + MatMPE = (_cmsStageMatrixData*) mpe ->Data; + mpe = mpe -> Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { + clut = (_cmsStageCLutData*) mpe -> Data; + mpe = mpe ->Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + // That should be all + if (mpe != NULL) { + cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8"); + return FALSE; + } + + + if (clut == NULL) + clutPoints = 0; + else + clutPoints = clut->Params->nSamples[0]; + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding + + + if (MatMPE != NULL) { + + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; + + } + else { + + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + } + + // The prelinearization table + if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; + + nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); + if (nTabSize > 0) { + + // The 3D CLUT. + if (clut != NULL) { + + for (j=0; j < nTabSize; j++) { + + val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } + } + } + + // The postlinearization table + if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + +// ******************************************************************************** +// Type cmsSigLut16Type +// ******************************************************************************** + +// Read 16 bit tables as gamma functions +static +cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries) +{ + cmsStage* mpe; + int i; + cmsToneCurve* Tables[cmsMAXCHANNELS]; + + // Maybe an empty table? (this is a lcms extension) + if (nEntries <= 0) return TRUE; + + // Check for malicious profiles + if (nChannels > cmsMAXCHANNELS) return FALSE; + + // Init table to zero + memset(Tables, 0, sizeof(Tables)); + + for (i=0; i < nChannels; i++) { + + Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL); + if (Tables[i] == NULL) goto Error; + + if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error; + } + + + // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) + mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); + if (mpe == NULL) goto Error; + + cmsPipelineInsertStage(lut, cmsAT_END, mpe); + + for (i=0; i < nChannels; i++) + cmsFreeToneCurve(Tables[i]); + + return TRUE; + +Error: + for (i=0; i < nChannels; i++) { + if (Tables[i]) cmsFreeToneCurve(Tables[i]); + } + + return FALSE; +} + +static +cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables) +{ + int j; + cmsUInt32Number i; + cmsUInt16Number val; + int nEntries = 256; + + nEntries = Tables->TheCurves[0]->nEntries; + + for (i=0; i < Tables ->nCurves; i++) { + + for (j=0; j < nEntries; j++) { + + if (Tables != NULL) + val = Tables->TheCurves[i]->Table16[j]; + else + val = _cmsQuantizeVal(j, nEntries); + + if (!_cmsWriteUInt16Number(io, val)) return FALSE; + } + } + return TRUE; + + cmsUNUSED_PARAMETER(ContextID); +} + +static +void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; + cmsPipeline* NewLUT = NULL; + cmsStage *mpemat, *mpeclut; + cmsUInt32Number nTabSize; + cmsFloat64Number Matrix[3*3]; + cmsUInt16Number InputEntries, OutputEntries; + + *nItems = 0; + + if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; + if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; + if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum + + // Padding + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + + // Do some checking + if (InputChannels > cmsMAXCHANNELS) goto Error; + if (OutputChannels > cmsMAXCHANNELS) goto Error; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); + if (NewLUT == NULL) goto Error; + + // Read the Matrix + if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; + + + // Only operates on 3 channels + + if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { + + mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); + if (mpemat == NULL) goto Error; + cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat); + } + + if (!_cmsReadUInt16Number(io, &InputEntries)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputEntries)) return NULL; + + + // Get input tables + if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error; + + // Get 3D CLUT + nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize > 0) { + + cmsUInt16Number *T; + + T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); + if (T == NULL) goto Error; + + if (!_cmsReadUInt16Array(io, nTabSize, T)) { + _cmsFree(self ->ContextID, T); + goto Error; + } + + mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); + if (mpeclut == NULL) { + _cmsFree(self ->ContextID, T); + goto Error; + } + + cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); + _cmsFree(self ->ContextID, T); + } + + + // Get output tables + if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error; + + *nItems = 1; + return NewLUT; + +Error: + if (NewLUT != NULL) cmsPipelineFree(NewLUT); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. +// Some empty defaults are created for missing parts + +static +cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number nTabSize; + cmsPipeline* NewLUT = (cmsPipeline*) Ptr; + cmsStage* mpe; + _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; + _cmsStageMatrixData* MatMPE = NULL; + _cmsStageCLutData* clut = NULL; + int InputChannels, OutputChannels, clutPoints; + + // Disassemble the LUT into components. + mpe = NewLUT -> Elements; + if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) { + + MatMPE = (_cmsStageMatrixData*) mpe ->Data; + mpe = mpe -> Next; + } + + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { + clut = (_cmsStageCLutData*) mpe -> Data; + mpe = mpe ->Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + // That should be all + if (mpe != NULL) { + cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16"); + return FALSE; + } + + InputChannels = cmsPipelineInputChannels(NewLUT); + OutputChannels = cmsPipelineOutputChannels(NewLUT); + + if (clut == NULL) + clutPoints = 0; + else + clutPoints = clut->Params->nSamples[0]; + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding + + + if (MatMPE != NULL) { + + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; + } + else { + + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + } + + + if (PreMPE != NULL) { + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; + } else { + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + } + + if (PostMPE != NULL) { + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; + } else { + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + + } + + // The prelinearization table + + if (PreMPE != NULL) { + if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; + } + + nTabSize = uipow(OutputChannels, clutPoints, InputChannels); + + if (nTabSize > 0) { + // The 3D CLUT. + if (clut != NULL) { + if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; + } + } + + // The postlinearization table + if (PostMPE != NULL) { + if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; + } + + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigLutAToBType +// ******************************************************************************** + + +// V4 stuff. Read matrix for LutAtoB and LutBtoA + +static +cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset) +{ + cmsFloat64Number dMat[3*3]; + cmsFloat64Number dOff[3]; + cmsStage* Mat; + + // Go to address + if (!io -> Seek(io, Offset)) return NULL; + + // Read the Matrix + if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL; + + if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL; + + Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff); + + return Mat; +} + + + + +// V4 stuff. Read CLUT part for LutAtoB and LutBtoA + +static +cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels) +{ + cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. + cmsUInt32Number GridPoints[cmsMAXCHANNELS], i; + cmsUInt8Number Precision; + cmsStage* CLUT; + _cmsStageCLutData* Data; + + if (!io -> Seek(io, Offset)) return NULL; + if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; + + for (i=0; i < cmsMAXCHANNELS; i++) + GridPoints[i] = gridPoints8[i]; + + if (!_cmsReadUInt8Number(io, &Precision)) return NULL; + + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + + CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL); + if (CLUT == NULL) return NULL; + + Data = (_cmsStageCLutData*) CLUT ->Data; + + // Precision can be 1 or 2 bytes + if (Precision == 1) { + + cmsUInt8Number v; + + for (i=0; i < Data ->nEntries; i++) { + + if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; + Data ->Tab.T[i] = FROM_8_TO_16(v); + } + + } + else + if (Precision == 2) { + + if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL; + } + else { + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return NULL; + } + + + return CLUT; +} + +static +cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) +{ + cmsTagTypeSignature BaseType; + cmsUInt32Number nItems; + + BaseType = _cmsReadTypeBase(io); + switch (BaseType) { + + case cmsSigCurveType: + return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0); + + case cmsSigParametricCurveType: + return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0); + + default: + { + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) BaseType); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); + } + return NULL; + } +} + + +// Read a set of curves from specific offset +static +cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) +{ + cmsToneCurve* Curves[cmsMAXCHANNELS]; + cmsUInt32Number i; + cmsStage* Lin = NULL; + + if (nCurves > cmsMAXCHANNELS) return FALSE; + + if (!io -> Seek(io, Offset)) return FALSE; + + for (i=0; i < nCurves; i++) + Curves[i] = NULL; + + for (i=0; i < nCurves; i++) { + + Curves[i] = ReadEmbeddedCurve(self, io); + if (Curves[i] == NULL) goto Error; + if (!_cmsReadAlignment(io)) goto Error; + } + + Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves); + +Error: + for (i=0; i < nCurves; i++) + cmsFreeToneCurve(Curves[i]); + + return Lin; +} + + +// LutAtoB type + +// This structure represents a colour transform. The type contains up to five processing +// elements which are stored in the AtoBTag tag in the following order: a set of one +// dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, +// a multidimensional lookup table, and a set of one dimensional output curves. +// Data are processed using these elements via the following sequence: +// +//("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves). +// +/* +It is possible to use any or all of these processing elements. At least one processing element +must be included.Only the following combinations are allowed: + +B +M - Matrix - B +A - CLUT - B +A - CLUT - M - Matrix - B + +*/ + +static +void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number BaseOffset; + cmsUInt8Number inputChan; // Number of input channels + cmsUInt8Number outputChan; // Number of output channels + cmsUInt32Number offsetB; // Offset to first "B" curve + cmsUInt32Number offsetMat; // Offset to matrix + cmsUInt32Number offsetM; // Offset to first "M" curve + cmsUInt32Number offsetC; // Offset to CLUT + cmsUInt32Number offsetA; // Offset to first "A" curve + cmsStage* mpe; + cmsPipeline* NewLUT = NULL; + + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; + if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; + + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + + if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); + if (NewLUT == NULL) return NULL; + + if (offsetA!= 0) { + mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan); + cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetC != 0) { + mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetM != 0) { + mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetMat != 0) { + mpe = ReadMatrix(self, io, BaseOffset + offsetMat); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetB != 0) { + mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + *nItems = 1; + return NewLUT; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// Write a set of curves +static +cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe) +{ + _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data; + + // Write the Matrix + if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE; + + if (m ->Offset != NULL) { + + if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE; + } + else { + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + + } + + + return TRUE; + + cmsUNUSED_PARAMETER(self); +} + + +// Write a set of curves +static +cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe) +{ + cmsUInt32Number i, n; + cmsTagTypeSignature CurrentType; + cmsToneCurve** Curves; + + + n = cmsStageOutputChannels(mpe); + Curves = _cmsStageGetPtrToCurveSet(mpe); + + for (i=0; i < n; i++) { + + // If this is a table-based curve, use curve type even on V4 + CurrentType = Type; + + if (Curves[i] ->nSegments == 0) + CurrentType = cmsSigCurveType; + else + if (Curves[i] ->Segments[0].Type < 0) + CurrentType = cmsSigCurveType; + + if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE; + + switch (CurrentType) { + + case cmsSigCurveType: + if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE; + break; + + case cmsSigParametricCurveType: + if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE; + break; + + default: + { + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) Type); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); + } + return FALSE; + } + + if (!_cmsWriteAlignment(io)) return FALSE; + } + + + return TRUE; +} + + +static +cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe) +{ + cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. + cmsUInt32Number i; + _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data; + + if (CLUT ->HasFloatValues) { + cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); + return FALSE; + } + + memset(gridPoints, 0, sizeof(gridPoints)); + for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) + gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i]; + + if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE; + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; + + // Precision can be 1 or 2 bytes + if (Precision == 1) { + + for (i=0; i < CLUT->nEntries; i++) { + + if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; + } + } + else + if (Precision == 2) { + + if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; + } + else { + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return FALSE; + } + + if (!_cmsWriteAlignment(io)) return FALSE; + + return TRUE; +} + + + + +static +cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsPipeline* Lut = (cmsPipeline*) Ptr; + int inputChan, outputChan; + cmsStage *A = NULL, *B = NULL, *M = NULL; + cmsStage * Matrix = NULL; + cmsStage * CLUT = NULL; + cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; + cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; + + // Get the base for all offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (Lut ->Elements != NULL) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, + cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { + + cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB"); + return FALSE; + } + + // Get input, output channels + inputChan = cmsPipelineInputChannels(Lut); + outputChan = cmsPipelineOutputChannels(Lut); + + // Write channel count + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + + // Keep directory to be filled latter + DirectoryPos = io ->Tell(io); + + // Write the directory + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + + if (A != NULL) { + + offsetA = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; + } + + if (CLUT != NULL) { + offsetC = io ->Tell(io) - BaseOffset; + if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; + + } + if (M != NULL) { + + offsetM = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; + } + + if (Matrix != NULL) { + offsetMat = io ->Tell(io) - BaseOffset; + if (!WriteMatrix(self, io, Matrix)) return FALSE; + } + + if (B != NULL) { + + offsetB = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; + } + + CurrentPos = io ->Tell(io); + + if (!io ->Seek(io, DirectoryPos)) return FALSE; + + if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; + + if (!io ->Seek(io, CurrentPos)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// LutBToA type + +static +void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number inputChan; // Number of input channels + cmsUInt8Number outputChan; // Number of output channels + cmsUInt32Number BaseOffset; // Actual position in file + cmsUInt32Number offsetB; // Offset to first "B" curve + cmsUInt32Number offsetMat; // Offset to matrix + cmsUInt32Number offsetM; // Offset to first "M" curve + cmsUInt32Number offsetC; // Offset to CLUT + cmsUInt32Number offsetA; // Offset to first "A" curve + cmsStage* mpe; + cmsPipeline* NewLUT = NULL; + + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; + if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; + + // Padding + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + + if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); + if (NewLUT == NULL) return NULL; + + if (offsetB != 0) { + mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetMat != 0) { + mpe = ReadMatrix(self, io, BaseOffset + offsetMat); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetM != 0) { + mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetC != 0) { + mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + if (offsetA!= 0) { + mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan); + if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + *nItems = 1; + return NewLUT; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +/* +B +B - Matrix - M +B - CLUT - A +B - Matrix - M - CLUT - A +*/ + +static +cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsPipeline* Lut = (cmsPipeline*) Ptr; + int inputChan, outputChan; + cmsStage *A = NULL, *B = NULL, *M = NULL; + cmsStage *Matrix = NULL; + cmsStage *CLUT = NULL; + cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; + cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; + + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { + cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA"); + return FALSE; + } + + inputChan = cmsPipelineInputChannels(Lut); + outputChan = cmsPipelineOutputChannels(Lut); + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + + DirectoryPos = io ->Tell(io); + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + + if (A != NULL) { + + offsetA = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; + } + + if (CLUT != NULL) { + offsetC = io ->Tell(io) - BaseOffset; + if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; + + } + if (M != NULL) { + + offsetM = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; + } + + if (Matrix != NULL) { + offsetMat = io ->Tell(io) - BaseOffset; + if (!WriteMatrix(self, io, Matrix)) return FALSE; + } + + if (B != NULL) { + + offsetB = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; + } + + CurrentPos = io ->Tell(io); + + if (!io ->Seek(io, DirectoryPos)) return FALSE; + + if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; + + if (!io ->Seek(io, CurrentPos)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + + +static +void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + + +// ******************************************************************************** +// Type cmsSigColorantTableType +// ******************************************************************************** +/* +The purpose of this tag is to identify the colorants used in the profile by a +unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous +value. The first colorant listed is the colorant of the first device channel of +a lut tag. The second colorant listed is the colorant of the second device channel +of a lut tag, and so on. +*/ + +static +void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number i, Count; + cmsNAMEDCOLORLIST* List; + char Name[34]; + cmsUInt16Number PCS[3]; + + + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + if (Count > cmsMAXCHANNELS) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count); + return NULL; + } + + List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", ""); + for (i=0; i < Count; i++) { + + if (io ->Read(io, Name, 32, 1) != 1) goto Error; + Name[33] = 0; + + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; + + if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; + + } + + *nItems = 1; + return List; + +Error: + *nItems = 0; + cmsFreeNamedColorList(List); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + + +// Saves a colorant table. It is using the named color structure for simplicity sake +static +cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; + int i, nColors; + + nColors = cmsNamedColorCount(NamedColorList); + + if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; + + for (i=0; i < nColors; i++) { + + char root[33]; + cmsUInt16Number PCS[3]; + + if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0; + root[32] = 0; + + if (!io ->Write(io, 32, root)) return FALSE; + if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; + return (void*) cmsDupNamedColorList(nc); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigNamedColor2Type +// ******************************************************************************** +// +//The namedColor2Type is a count value and array of structures that provide color +//coordinates for 7-bit ASCII color names. For each named color, a PCS and optional +//device representation of the color are given. Both representations are 16-bit values. +//The device representation corresponds to the header’s “color space of data” field. +//This representation should be consistent with the “number of device components” +//field in the namedColor2Type. If this field is 0, device coordinates are not provided. +//The PCS representation corresponds to the header’s PCS field. The PCS representation +//is always provided. Color names are fixed-length, 32-byte fields including null +//termination. In order to maintain maximum portability, it is strongly recommended +//that special characters of the 7-bit ASCII set not be used. + +static +void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + + cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use + cmsUInt32Number count; // Count of named colors + cmsUInt32Number nDeviceCoords; // Num of device coordinates + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name + cmsNAMEDCOLORLIST* v; + cmsUInt32Number i; + + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL; + if (!_cmsReadUInt32Number(io, &count)) return NULL; + if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL; + + if (io -> Read(io, prefix, 32, 1) != 1) return NULL; + if (io -> Read(io, suffix, 32, 1) != 1) return NULL; + + prefix[31] = suffix[31] = 0; + + v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix); + if (v == NULL) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count); + return NULL; + } + + if (nDeviceCoords > cmsMAXCHANNELS) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); + return 0; + } + for (i=0; i < count; i++) { + + cmsUInt16Number PCS[3]; + cmsUInt16Number Colorant[cmsMAXCHANNELS]; + char Root[33]; + + memset(Colorant, 0, sizeof(Colorant)); + if (io -> Read(io, Root, 32, 1) != 1) return NULL; + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; + if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; + + if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error; + } + + *nItems = 1; + return (void*) v ; + +Error: + cmsFreeNamedColorList(v); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +// Saves a named color list into a named color profile +static +cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name + int i, nColors; + + nColors = cmsNamedColorCount(NamedColorList); + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; + if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE; + + strncpy(prefix, (const char*) NamedColorList->Prefix, 32); + strncpy(suffix, (const char*) NamedColorList->Suffix, 32); + + suffix[31] = prefix[31] = 0; + + if (!io ->Write(io, 32, prefix)) return FALSE; + if (!io ->Write(io, 32, suffix)) return FALSE; + + for (i=0; i < nColors; i++) { + + cmsUInt16Number PCS[3]; + cmsUInt16Number Colorant[cmsMAXCHANNELS]; + char Root[33]; + + if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; + if (!io ->Write(io, 32 , Root)) return FALSE; + if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; + if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; + + return (void*) cmsDupNamedColorList(nc); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigProfileSequenceDescType +// ******************************************************************************** + +// This type is an array of structures, each of which contains information from the +// header fields and tags from the original profiles which were combined to create +// the final profile. The order of the structures is the order in which the profiles +// were combined and includes a structure for the final profile. This provides a +// description of the profile sequence from source to destination, +// typically used with the DeviceLink profile. + +static +cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag) +{ + cmsTagTypeSignature BaseType; + cmsUInt32Number nItems; + + BaseType = _cmsReadTypeBase(io); + + switch (BaseType) { + + case cmsSigTextType: + if (*mlu) cmsMLUfree(*mlu); + *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag); + return (*mlu != NULL); + + case cmsSigTextDescriptionType: + if (*mlu) cmsMLUfree(*mlu); + *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag); + return (*mlu != NULL); + + /* + TBD: Size is needed for MLU, and we have no idea on which is the available size + */ + + case cmsSigMultiLocalizedUnicodeType: + if (*mlu) cmsMLUfree(*mlu); + *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag); + return (*mlu != NULL); + + default: return FALSE; + } +} + + +static +void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsSEQ* OutSeq; + cmsUInt32Number i, Count; + + *nItems = 0; + + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + + OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); + if (OutSeq == NULL) return NULL; + + OutSeq ->n = Count; + + // Get structures as well + + for (i=0; i < Count; i++) { + + cmsPSEQDESC* sec = &OutSeq -> seq[i]; + + if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + if (!_cmsReadUInt64Number(io, &sec ->attributes)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt64Number); + + if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) return NULL; + if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) return NULL; + } + + *nItems = 1; + return OutSeq; +} + + +// Aux--Embed a text description type. It can be of type text description or multilocalized unicode +// and it depends of the version number passed on cmsTagDescriptor structure instead of stack +static +cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text) +{ + if (self ->ICCVersion < 0x4000000) { + + if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; + return Type_Text_Description_Write(self, io, Text, 1); + } + else { + if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE; + return Type_MLU_Write(self, io, Text, 1); + } +} + + +static +cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsSEQ* Seq = (cmsSEQ*) Ptr; + cmsUInt32Number i; + + if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE; + + for (i=0; i < Seq ->n; i++) { + + cmsPSEQDESC* sec = &Seq -> seq[i]; + + if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; + if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; + if (!_cmsWriteUInt64Number(io, sec ->attributes)) return FALSE; + if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; + + if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; + if (!SaveDescription(self, io, sec ->Model)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigProfileSequenceIdType +// ******************************************************************************** +/* +In certain workflows using ICC Device Link Profiles, it is necessary to identify the +original profiles that were combined to create the Device Link Profile. +This type is an array of structures, each of which contains information for +identification of a profile used in a sequence +*/ + + +static +cmsBool ReadSeqID(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsSEQ* OutSeq = (cmsSEQ*) Cargo; + cmsPSEQDESC* seq = &OutSeq ->seq[n]; + + if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE; + if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE; + + return TRUE; +} + + + +static +void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsSEQ* OutSeq; + cmsUInt32Number Count; + cmsUInt32Number BaseOffset; + + *nItems = 0; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Get table count + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Allocate an empty structure + OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); + if (OutSeq == NULL) return NULL; + + + // Read the position table + if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) { + + cmsFreeProfileSequenceDescription(OutSeq); + return NULL; + } + + // Success + *nItems = 1; + return OutSeq; + +} + + +static +cmsBool WriteSeqID(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsSEQ* Seq = (cmsSEQ*) Cargo; + + if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE; + + // Store here the MLU + if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsSEQ* Seq = (cmsSEQ*) Ptr; + cmsUInt32Number BaseOffset; + + // Keep the base offset + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // This is the table count + if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE; + + // This is the position table and content + if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigUcrBgType +// ******************************************************************************** +/* +This type contains curves representing the under color removal and black +generation and a text string which is a general description of the method used +for the ucr/bg. +*/ + +static +void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); + cmsUInt32Number CountUcr, CountBg; + char* ASCIIString; + + *nItems = 0; + if (n == NULL) return NULL; + + // First curve is Under color removal + if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL); + if (n ->Ucr == NULL) return NULL; + + if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= CountUcr * sizeof(cmsUInt16Number); + + // Second curve is Black generation + if (!_cmsReadUInt32Number(io, &CountBg)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL); + if (n ->Bg == NULL) return NULL; + if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL; + if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL; + SizeOfTag -= CountBg * sizeof(cmsUInt16Number); + if (SizeOfTag == UINT_MAX) return NULL; + + // Now comes the text. The length is specified by the tag size + n ->Desc = cmsMLUalloc(self ->ContextID, 1); + if (n ->Desc == NULL) return NULL; + + ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); + if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL; + ASCIIString[SizeOfTag] = 0; + cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString); + _cmsFree(self ->ContextID, ASCIIString); + + *nItems = 1; + return (void*) n; +} + +static +cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUcrBg* Value = (cmsUcrBg*) Ptr; + cmsUInt32Number TextSize; + char* Text; + + // First curve is Under color removal + if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE; + if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE; + + // Then black generation + if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE; + if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE; + + // Now comes the text. The length is specified by the tag size + TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0); + Text = (char*) _cmsMalloc(self ->ContextID, TextSize); + if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE; + + if (!io ->Write(io, TextSize, Text)) return FALSE; + _cmsFree(self ->ContextID, Text); + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + cmsUcrBg* Src = (cmsUcrBg*) Ptr; + cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); + + if (NewUcrBg == NULL) return NULL; + + NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg); + NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr); + NewUcrBg ->Desc = cmsMLUdup(Src ->Desc); + + return (void*) NewUcrBg; + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsUcrBg* Src = (cmsUcrBg*) Ptr; + + if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr); + if (Src ->Bg) cmsFreeToneCurve(Src ->Bg); + if (Src ->Desc) cmsMLUfree(Src ->Desc); + + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigCrdInfoType +// ******************************************************************************** + +/* +This type contains the PostScript product name to which this profile corresponds +and the names of the companion CRDs. Recall that a single profile can generate +multiple CRDs. It is implemented as a MLU being the language code "PS" and then +country varies for each element: + + nm: PostScript product name + #0: Rendering intent 0 CRD name + #1: Rendering intent 1 CRD name + #2: Rendering intent 2 CRD name + #3: Rendering intent 3 CRD name +*/ + + + +// Auxiliar, read an string specified as count + string +static +cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section) +{ + cmsUInt32Number Count; + char* Text; + + if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; + + if (!_cmsReadUInt32Number(io, &Count)) return FALSE; + + if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE; + if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; + + Text = (char*) _cmsMalloc(self ->ContextID, Count+1); + if (Text == NULL) return FALSE; + + if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) { + _cmsFree(self ->ContextID, Text); + return FALSE; + } + + Text[Count] = 0; + + cmsMLUsetASCII(mlu, "PS", Section, Text); + _cmsFree(self ->ContextID, Text); + + *SizeOfTag -= (Count + sizeof(cmsUInt32Number)); + return TRUE; +} + +static +cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section) +{ + cmsUInt32Number TextSize; + char* Text; + + TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0); + Text = (char*) _cmsMalloc(self ->ContextID, TextSize); + + if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; + + if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE; + + if (!io ->Write(io, TextSize, Text)) return FALSE; + _cmsFree(self ->ContextID, Text); + + return TRUE; +} + +static +void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5); + + *nItems = 0; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error; + + *nItems = 1; + return (void*) mlu; + +Error: + cmsMLUfree(mlu); + return NULL; + +} + +static +cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + + cmsMLU* mlu = (cmsMLU*) Ptr; + + if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error; + + return TRUE; + +Error: + return FALSE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsMLUfree((cmsMLU*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + +// ******************************************************************************** +// Type cmsSigScreeningType +// ******************************************************************************** +// +//The screeningType describes various screening parameters including screen +//frequency, screening angle, and spot shape. + +static +void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsScreening* sc = NULL; + cmsUInt32Number i; + + sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening)); + if (sc == NULL) return NULL; + + *nItems = 0; + + if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error; + if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error; + + if (sc ->nChannels > cmsMAXCHANNELS - 1) + sc ->nChannels = cmsMAXCHANNELS - 1; + + for (i=0; i < sc ->nChannels; i++) { + + if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; + if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; + if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error; + } + + + *nItems = 1; + + return (void*) sc; + +Error: + if (sc != NULL) + _cmsFree(self ->ContextID, sc); + + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsScreening* sc = (cmsScreening* ) Ptr; + cmsUInt32Number i; + + if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE; + if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE; + + for (i=0; i < sc ->nChannels; i++) { + + if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE; + if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigViewingConditionsType +// ******************************************************************************** +// +//This type represents a set of viewing condition parameters including: +//CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’ +//surround tristimulus values. + +static +void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsICCViewingConditions* vc = NULL; + + vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions)); + if (vc == NULL) return NULL; + + *nItems = 0; + + if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error; + if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error; + if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error; + + *nItems = 1; + + return (void*) vc; + +Error: + if (vc != NULL) + _cmsFree(self ->ContextID, vc); + + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; + + if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE; + if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE; + if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigMultiProcessElementType +// ******************************************************************************** + + +static +void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsStageDup((cmsStage*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsStageFree((cmsStage*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + +// Each curve is stored in one or more curve segments, with break-points specified between curve segments. +// The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The +// first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be +// specified either in terms of a formula, or by a sampled curve. + + +// Read an embedded segmented curve +static +cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) +{ + cmsCurveSegSignature ElementSig; + cmsUInt32Number i, j; + cmsUInt16Number nSegments; + cmsCurveSegment* Segments; + cmsToneCurve* Curve; + cmsFloat32Number PrevBreak = -1E22F; // - infinite + + // Take signature and channels for each element. + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; + + // That should be a segmented curve + if (ElementSig != cmsSigSegmentedCurve) return NULL; + + if (!_cmsReadUInt32Number(io, NULL)) return NULL; + if (!_cmsReadUInt16Number(io, &nSegments)) return NULL; + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + + if (nSegments < 1) return NULL; + Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment)); + if (Segments == NULL) return NULL; + + // Read breakpoints + for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) { + + Segments[i].x0 = PrevBreak; + if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error; + PrevBreak = Segments[i].x1; + } + + Segments[nSegments-1].x0 = PrevBreak; + Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number + + // Read segments + for (i=0; i < nSegments; i++) { + + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error; + if (!_cmsReadUInt32Number(io, NULL)) goto Error; + + switch (ElementSig) { + + case cmsSigFormulaCurveSeg: { + + cmsUInt16Number Type; + cmsUInt32Number ParamsByType[] = {4, 5, 5 }; + + if (!_cmsReadUInt16Number(io, &Type)) goto Error; + if (!_cmsReadUInt16Number(io, NULL)) goto Error; + + Segments[i].Type = Type + 6; + if (Type > 2) goto Error; + + for (j=0; j < ParamsByType[Type]; j++) { + + cmsFloat32Number f; + if (!_cmsReadFloat32Number(io, &f)) goto Error; + Segments[i].Params[j] = f; + } + } + break; + + + case cmsSigSampledCurveSeg: { + cmsUInt32Number Count; + + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + Segments[i].nGridPoints = Count; + Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); + if (Segments[i].SampledPoints == NULL) goto Error; + + for (j=0; j < Count; j++) { + if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; + } + } + break; + + default: + { + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); + } + return NULL; + + } + } + + Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments); + + for (i=0; i < nSegments; i++) { + if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); + } + _cmsFree(self ->ContextID, Segments); + return Curve; + +Error: + if (Segments) _cmsFree(self ->ContextID, Segments); + return NULL; +} + + +static +cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo; + + GammaTables[n] = ReadSegmentedCurve(self, io); + return (GammaTables[n] != NULL); + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsStage* mpe = NULL; + cmsUInt16Number InputChans, OutputChans; + cmsUInt32Number i, BaseOffset; + cmsToneCurve** GammaTables; + + *nItems = 0; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + if (InputChans != OutputChans) return NULL; + + GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*)); + if (GammaTables == NULL) return NULL; + + if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) { + + mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables); + } + else { + mpe = NULL; + } + + for (i=0; i < InputChans; i++) { + if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]); + } + + _cmsFree(self ->ContextID, GammaTables); + *nItems = (mpe != NULL) ? 1 : 0; + return mpe; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +// Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY +static +cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) +{ + cmsUInt32Number i, j; + cmsCurveSegment* Segments = g ->Segments; + cmsUInt32Number nSegments = g ->nSegments; + + if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + + // Write the break-points + for (i=0; i < nSegments - 1; i++) { + if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error; + } + + // Write the segments + for (i=0; i < g ->nSegments; i++) { + + cmsCurveSegment* ActualSeg = Segments + i; + + if (ActualSeg -> Type == 0) { + + // This is a sampled curve + if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error; + + for (j=0; j < g ->Segments[i].nGridPoints; j++) { + if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error; + } + + } + else { + int Type; + cmsUInt32Number ParamsByType[] = { 4, 5, 5 }; + + // This is a formula-based + if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + + // We only allow 1, 2 and 3 as types + Type = ActualSeg ->Type - 6; + if (Type > 2 || Type < 0) goto Error; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error; + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + + for (j=0; j < ParamsByType[Type]; j++) { + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error; + } + } + + // It seems there is no need to align. Code is here, and for safety commented out + // if (!_cmsWriteAlignment(io)) goto Error; + } + + return TRUE; + +Error: + return FALSE; +} + + +static +cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo; + + return WriteSegmentedCurve(io, Curves ->TheCurves[n]); + + cmsUNUSED_PARAMETER(SizeOfTag); + cmsUNUSED_PARAMETER(self); +} + +// Write a curve, checking first for validity +static +cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number BaseOffset; + cmsStage* mpe = (cmsStage*) Ptr; + _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data; + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Write the header. Since those are curves, input and output channels are same + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + + if (!WritePositionTable(self, io, 0, + mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE; + + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + + +// The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the +// matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array +// is organized as follows: +// array = [e11, e12, …, e1P, e21, e22, …, e2P, …, eQ1, eQ2, …, eQP, e1, e2, …, eQ] + +static +void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsStage* mpe; + cmsUInt16Number InputChans, OutputChans; + cmsUInt32Number nElems, i; + cmsFloat64Number* Matrix; + cmsFloat64Number* Offsets; + + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + + nElems = InputChans * OutputChans; + + // Input and output chans may be ANY (up to 0xffff) + Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); + if (Matrix == NULL) return NULL; + + Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number)); + if (Offsets == NULL) { + + _cmsFree(self ->ContextID, Matrix); + return NULL; + } + + for (i=0; i < nElems; i++) { + + cmsFloat32Number v; + + if (!_cmsReadFloat32Number(io, &v)) return NULL; + Matrix[i] = v; + } + + + for (i=0; i < OutputChans; i++) { + + cmsFloat32Number v; + + if (!_cmsReadFloat32Number(io, &v)) return NULL; + Offsets[i] = v; + } + + + mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets); + _cmsFree(self ->ContextID, Matrix); + _cmsFree(self ->ContextID, Offsets); + + *nItems = 1; + + return mpe; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number i, nElems; + cmsStage* mpe = (cmsStage*) Ptr; + _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; + + nElems = mpe ->InputChannels * mpe ->OutputChannels; + + for (i=0; i < nElems; i++) { + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; + } + + + for (i=0; i < mpe ->OutputChannels; i++) { + + if (Matrix ->Offset == NULL) { + + if (!_cmsWriteFloat32Number(io, 0)) return FALSE; + } + else { + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + + +static +void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsStage* mpe = NULL; + cmsUInt16Number InputChans, OutputChans; + cmsUInt8Number Dimensions8[16]; + cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS]; + _cmsStageCLutData* clut; + + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) + goto Error; + + // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number + nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; + for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i]; + + // Allocate the true CLUT + mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); + if (mpe == NULL) goto Error; + + // Read the data + clut = (_cmsStageCLutData*) mpe ->Data; + for (i=0; i < clut ->nEntries; i++) { + + if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error; + } + + *nItems = 1; + return mpe; + +Error: + *nItems = 0; + if (mpe != NULL) cmsStageFree(mpe); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// Write a CLUT in floating point +static +cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt8Number Dimensions8[16]; + cmsUInt32Number i; + cmsStage* mpe = (cmsStage*) Ptr; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data; + + // Check for maximum number of channels + if (mpe -> InputChannels > 15) return FALSE; + + // Only floats are supported in MPE + if (clut ->HasFloatValues == FALSE) return FALSE; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; + + memset(Dimensions8, 0, sizeof(Dimensions8)); + + for (i=0; i < mpe ->InputChannels; i++) + Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i]; + + if (!io ->Write(io, 16, Dimensions8)) return FALSE; + + for (i=0; i < clut ->nEntries; i++) { + + if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + + +// This is the list of built-in MPE types +static _cmsTagTypeLinkedList SupportedMPEtypes[] = { + +{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[1] }, // Ignore those elements for now +{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[2] }, // (That's what the spec says) + +{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] }, +{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] }, +{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, +}; + +#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList)) + +static +cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsStageSignature ElementSig; + cmsTagTypeHandler* TypeHandler; + cmsStage *mpe = NULL; + cmsUInt32Number nItems; + cmsPipeline *NewLUT = (cmsPipeline *) Cargo; + + // Take signature and channels for each element. + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; + + // The reserved placeholder + if (!_cmsReadUInt32Number(io, NULL)) return FALSE; + + // Read diverse MPE types + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + if (TypeHandler == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + + // An unknown element was found. + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String); + return FALSE; + } + + // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType) + // Read the MPE. No size is given + if (TypeHandler ->ReadPtr != NULL) { + + // This is a real element which should be read and processed + mpe = (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag); + if (mpe == NULL) return FALSE; + + // All seems ok, insert element + cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + } + + return TRUE; + + cmsUNUSED_PARAMETER(SizeOfTag); + cmsUNUSED_PARAMETER(n); +} + + +// This is the main dispatcher for MPE +static +void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt16Number InputChans, OutputChans; + cmsUInt32Number ElementCount; + cmsPipeline *NewLUT = NULL; + cmsUInt32Number BaseOffset; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Read channels and element count + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); + if (NewLUT == NULL) return NULL; + + if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL; + + if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) { + if (NewLUT != NULL) cmsPipelineFree(NewLUT); + *nItems = 0; + return NULL; + } + + // Success + *nItems = 1; + return NewLUT; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + + +// This one is a liitle bit more complex, so we don't use position tables this time. +static +cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos; + int inputChan, outputChan; + cmsUInt32Number ElemCount; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before; + cmsStageSignature ElementSig; + cmsPipeline* Lut = (cmsPipeline*) Ptr; + cmsStage* Elem = Lut ->Elements; + cmsTagTypeHandler* TypeHandler; + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + inputChan = cmsPipelineInputChannels(Lut); + outputChan = cmsPipelineOutputChannels(Lut); + ElemCount = cmsPipelineStageCount(Lut); + + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *)); + if (ElementOffsets == NULL) goto Error; + + ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *)); + if (ElementSizes == NULL) goto Error; + + // Write the head + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error; + if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error; + + DirectoryPos = io ->Tell(io); + + // Write a fake directory to be filled latter on + for (i=0; i < ElemCount; i++) { + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size + } + + // Write each single tag. Keep track of the size as well. + for (i=0; i < ElemCount; i++) { + + ElementOffsets[i] = io ->Tell(io) - BaseOffset; + + ElementSig = Elem ->Type; + + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + if (TypeHandler == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + + // An unknow element was found. + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String); + goto Error; + } + + if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + Before = io ->Tell(io); + if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error; + if (!_cmsWriteAlignment(io)) goto Error; + + ElementSizes[i] = io ->Tell(io) - Before; + + Elem = Elem ->Next; + } + + // Write the directory + CurrentPos = io ->Tell(io); + + if (!io ->Seek(io, DirectoryPos)) goto Error; + + for (i=0; i < ElemCount; i++) { + if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; + } + + if (!io ->Seek(io, CurrentPos)) goto Error; + + if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); + return TRUE; + +Error: + if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); + return FALSE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigVcgtType +// ******************************************************************************** + + +#define cmsVideoCardGammaTableType 0 +#define cmsVideoCardGammaFormulaType 1 + +// Used internally +typedef struct { + double Gamma; + double Min; + double Max; +} _cmsVCGTGAMMA; + + +static +void *Type_vcgt_Read(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, + cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number TagType, n, i; + cmsToneCurve** Curves; + + *nItems = 0; + + // Read tag type + if (!_cmsReadUInt32Number(io, &TagType)) return NULL; + + // Allocate space for the array + Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); + if (Curves == NULL) return NULL; + + // There are two possible flavors + switch (TagType) { + + // Gamma is stored as a table + case cmsVideoCardGammaTableType: + { + cmsUInt16Number nChannels, nElems, nBytes; + + // Check channel count, which should be 3 (we don't support monochrome this time) + if (!_cmsReadUInt16Number(io, &nChannels)) goto Error; + + if (nChannels != 3) { + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels); + goto Error; + } + + // Get Table element count and bytes per element + if (!_cmsReadUInt16Number(io, &nElems)) goto Error; + if (!_cmsReadUInt16Number(io, &nBytes)) goto Error; + + // Adobe's quirk fixup. Fixing broken profiles... + if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) + nBytes = 2; + + + // Populate tone curves + for (n=0; n < 3; n++) { + + Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL); + if (Curves[n] == NULL) goto Error; + + // On depending on byte depth + switch (nBytes) { + + // One byte, 0..255 + case 1: + for (i=0; i < nElems; i++) { + + cmsUInt8Number v; + + if (!_cmsReadUInt8Number(io, &v)) goto Error; + Curves[n] ->Table16[i] = FROM_8_TO_16(v); + } + break; + + // One word 0..65535 + case 2: + if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error; + break; + + // Unsupported + default: + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8); + goto Error; + } + } // For all 3 channels + } + break; + + // In this case, gamma is stored as a formula + case cmsVideoCardGammaFormulaType: + { + _cmsVCGTGAMMA Colorant[3]; + + // Populate tone curves + for (n=0; n < 3; n++) { + + double Params[10]; + + if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error; + if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error; + if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error; + + // Parametric curve type 5 is: + // Y = (aX + b)^Gamma + e | X >= d + // Y = cX + f | X < d + + // vcgt formula is: + // Y = (Max – Min) * (X ^ Gamma) + Min + + // So, the translation is + // a = (Max – Min) ^ ( 1 / Gamma) + // e = Min + // b=c=d=f=0 + + Params[0] = Colorant[n].Gamma; + Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma)); + Params[2] = 0; + Params[3] = 0; + Params[4] = 0; + Params[5] = Colorant[n].Min; + Params[6] = 0; + + Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params); + if (Curves[n] == NULL) goto Error; + } + } + break; + + // Unsupported + default: + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType); + goto Error; + } + + *nItems = 1; + return (void*) Curves; + +// Regret, free all resources +Error: + + cmsFreeToneCurveTriple(Curves); + _cmsFree(self ->ContextID, Curves); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +// We don't support all flavors, only 16bits tables and formula +static +cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsToneCurve** Curves = (cmsToneCurve**) Ptr; + cmsUInt32Number i, j; + + if (cmsGetToneCurveParametricType(Curves[0]) == 5 && + cmsGetToneCurveParametricType(Curves[1]) == 5 && + cmsGetToneCurveParametricType(Curves[2]) == 5) { + + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; + + // Save parameters + for (i=0; i < 3; i++) { + + _cmsVCGTGAMMA v; + + v.Gamma = Curves[i] ->Segments[0].Params[0]; + v.Min = Curves[i] ->Segments[0].Params[5]; + v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min; + + if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE; + } + } + + else { + + // Always store as a table of 256 words + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; + if (!_cmsWriteUInt16Number(io, 3)) return FALSE; + if (!_cmsWriteUInt16Number(io, 256)) return FALSE; + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; + + for (i=0; i < 3; i++) { + for (j=0; j < 256; j++) { + + cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0)); + cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0); + + if (!_cmsWriteUInt16Number(io, n)) return FALSE; + } + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(self); + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr; + cmsToneCurve** NewCurves; + + NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); + if (NewCurves == NULL) return NULL; + + NewCurves[0] = cmsDupToneCurve(OldCurves[0]); + NewCurves[1] = cmsDupToneCurve(OldCurves[1]); + NewCurves[2] = cmsDupToneCurve(OldCurves[2]); + + return (void*) NewCurves; + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeToneCurveTriple((cmsToneCurve**) Ptr); + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type support main routines +// ******************************************************************************** + + +// This is the list of built-in types +static _cmsTagTypeLinkedList SupportedTagTypes[] = { + +{TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] }, +{TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] }, +{TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] }, +{TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] }, +{TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] }, +{TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] }, +{TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] }, +{TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] }, +{TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] }, +{TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] }, +{TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] }, +{TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] }, +{TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] }, +{TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] }, +{TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] }, +{TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] }, +{TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] }, +{TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] }, +{TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] }, +{TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] }, +{TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] }, +{TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] }, +{TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] }, +{TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] }, +{TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] }, +{TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] }, +{TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] }, +{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] }, +{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] }, +{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } +}; + +#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList)) + +// Both kind of plug-ins share same structure +cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Data) +{ + return RegisterTypesPlugin(Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); +} + +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Data) +{ + return RegisterTypesPlugin(Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); +} + + +// Wrapper for tag types +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig) +{ + return GetHandler(sig, SupportedTagTypes); +} + +// ******************************************************************************** +// Tag support main routines +// ******************************************************************************** + +typedef struct _cmsTagLinkedList_st { + + cmsTagSignature Signature; + cmsTagDescriptor Descriptor; + struct _cmsTagLinkedList_st* Next; + +} _cmsTagLinkedList; + +// This is the list of built-in tags +static _cmsTagLinkedList SupportedTags[] = { + + { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, + { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]}, + { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]}, + { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]}, + { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]}, + { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]}, + + // Allow corbis and its broken XYZ type + { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]}, + { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]}, + { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]}, + + { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]}, + { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]}, + { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, + + { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]}, + { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]}, + + { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]}, + { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]}, + { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]}, + { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]}, + { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]}, + + { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]}, + { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]}, + + { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]}, + { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]}, + + { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]}, + + { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]}, + { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]}, + + { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]}, + { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]}, + + { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]}, + + { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]}, + { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]}, + { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]}, + + { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]}, + { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]}, + { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]}, + + { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]}, + { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]}, + { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]}, + + { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]}, + + { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, + { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, + { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, + { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, + { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, + { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, + + { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]}, + + { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, + { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, + + { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, + { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, + { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, + { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, + { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, + { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, + { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, + { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, + + { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, + { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, + + { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, + { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, + { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL}, NULL} + +}; + +/* + Not supported Why + ======================= ========================================= + cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! + cmsSigNamedColorTag ==> Deprecated + cmsSigDataTag ==> Ancient, unused + cmsSigDeviceSettingsTag ==> Deprecated, useless +*/ + +#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList)) + +cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data) +{ + cmsPluginTag* Plugin = (cmsPluginTag*) Data; + _cmsTagLinkedList *pt, *Anterior; + + + if (Data == NULL) { + + SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL; + return TRUE; + } + + pt = Anterior = SupportedTags; + while (pt != NULL) { + + if (Plugin->Signature == pt -> Signature) { + pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour + return TRUE; + } + + Anterior = pt; + pt = pt ->Next; + } + + pt = (_cmsTagLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagLinkedList)); + if (pt == NULL) return FALSE; + + pt ->Signature = Plugin ->Signature; + pt ->Descriptor = Plugin ->Descriptor; + pt ->Next = NULL; + + if (Anterior != NULL) Anterior -> Next = pt; + + return TRUE; +} + +// Return a descriptor for a given tag or NULL +cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig) +{ + _cmsTagLinkedList* pt; + + for (pt = SupportedTags; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } + + return NULL; +} + diff --git a/thirdparty/liblcms2/src/cmsvirt.c b/thirdparty/liblcms2/src/cmsvirt.c new file mode 100644 index 00000000..807bd223 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsvirt.c @@ -0,0 +1,1148 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Virtual (built-in) profiles +// ----------------------------------------------------------------------------------- + +static +cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description) +{ + cmsMLU *DescriptionMLU, *CopyrightMLU; + cmsBool rc = FALSE; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + DescriptionMLU = cmsMLUalloc(ContextID, 1); + CopyrightMLU = cmsMLUalloc(ContextID, 1); + + if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error; + + if (!cmsMLUsetWide(DescriptionMLU, "en", "US", Description)) goto Error; + if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error; + + if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error; + if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error; + + rc = TRUE; + +Error: + + if (DescriptionMLU) + cmsMLUfree(DescriptionMLU); + if (CopyrightMLU) + cmsMLUfree(CopyrightMLU); + return rc; +} + + +static +cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) +{ + cmsBool rc = FALSE; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1); + + if (Seq == NULL) return FALSE; + + Seq->seq[0].deviceMfg = (cmsSignature) 0; + Seq->seq[0].deviceModel = (cmsSignature) 0; + +#ifdef CMS_DONT_USE_INT64 + Seq->seq[0].attributes[0] = 0; + Seq->seq[0].attributes[1] = 0; +#else + Seq->seq[0].attributes = 0; +#endif + + Seq->seq[0].technology = (cmsTechnologySignature) 0; + + cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS"); + cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model); + + if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error; + + rc = TRUE; + +Error: + if (Seq) + cmsFreeProfileSequenceDescription(Seq); + + return rc; +} + + + +// This function creates a profile based on White point, primaries and +// transfer functions. +cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]) +{ + cmsHPROFILE hICC; + cmsMAT3 MColorants; + cmsCIEXYZTRIPLE Colorants; + cmsCIExyY MaxWhite; + cmsMAT3 CHAD; + cmsCIEXYZ WhitePointXYZ; + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetProfileVersion(hICC, 4.2); + + cmsSetDeviceClass(hICC, cmsSigDisplayClass); + cmsSetColorSpace(hICC, cmsSigRgbData); + cmsSetPCS(hICC, cmsSigXYZData); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Implement profile using following tags: + // + // 1 cmsSigProfileDescriptionTag + // 2 cmsSigMediaWhitePointTag + // 3 cmsSigRedColorantTag + // 4 cmsSigGreenColorantTag + // 5 cmsSigBlueColorantTag + // 6 cmsSigRedTRCTag + // 7 cmsSigGreenTRCTag + // 8 cmsSigBlueTRCTag + // 9 Chromatic adaptation Tag + // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II) + // 10 cmsSigChromaticityTag + + + if (!SetTextTags(hICC, L"RGB built-in")) goto Error; + + if (WhitePoint) { + + if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; + + cmsxyY2XYZ(&WhitePointXYZ, WhitePoint); + _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ()); + + // This is a V4 tag, but many CMM does read and understand it no matter which version + if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error; + } + + if (WhitePoint && Primaries) { + + MaxWhite.x = WhitePoint -> x; + MaxWhite.y = WhitePoint -> y; + MaxWhite.Y = 1.0; + + if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error; + + Colorants.Red.X = MColorants.v[0].n[0]; + Colorants.Red.Y = MColorants.v[1].n[0]; + Colorants.Red.Z = MColorants.v[2].n[0]; + + Colorants.Green.X = MColorants.v[0].n[1]; + Colorants.Green.Y = MColorants.v[1].n[1]; + Colorants.Green.Z = MColorants.v[2].n[1]; + + Colorants.Blue.X = MColorants.v[0].n[2]; + Colorants.Blue.Y = MColorants.v[1].n[2]; + Colorants.Blue.Z = MColorants.v[2].n[2]; + + if (!cmsWriteTag(hICC, cmsSigRedColorantTag, (void*) &Colorants.Red)) goto Error; + if (!cmsWriteTag(hICC, cmsSigBlueColorantTag, (void*) &Colorants.Blue)) goto Error; + if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error; + } + + + if (TransferFunction) { + + if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; + if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; + if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; + } + + if (Primaries) { + if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error; + } + + + return hICC; + +Error: + if (hICC) + cmsCloseProfile(hICC); + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]) +{ + return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction); +} + + + +// This function creates a profile based on White point and transfer function. +cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction) +{ + cmsHPROFILE hICC; + cmsCIEXYZ tmp; + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetProfileVersion(hICC, 4.2); + + cmsSetDeviceClass(hICC, cmsSigDisplayClass); + cmsSetColorSpace(hICC, cmsSigGrayData); + cmsSetPCS(hICC, cmsSigXYZData); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Implement profile using following tags: + // + // 1 cmsSigProfileDescriptionTag + // 2 cmsSigMediaWhitePointTag + // 3 cmsSigGrayTRCTag + + // This conforms a standard Gray DisplayProfile + + // Fill-in the tags + + if (!SetTextTags(hICC, L"gray built-in")) goto Error; + + + if (WhitePoint) { + + cmsxyY2XYZ(&tmp, WhitePoint); + if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error; + } + + if (TransferFunction) { + + if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error; + } + + return hICC; + +Error: + if (hICC) + cmsCloseProfile(hICC); + return NULL; +} + + + +cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction) +{ + return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction); +} + +// This is a devicelink operating in the target colorspace with as many transfer functions as components + +cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]) +{ + cmsHPROFILE hICC; + cmsPipeline* Pipeline; + cmsStage* Lin; + int nChannels; + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) + return NULL; + + cmsSetProfileVersion(hICC, 4.2); + + cmsSetDeviceClass(hICC, cmsSigLinkClass); + cmsSetColorSpace(hICC, ColorSpace); + cmsSetPCS(hICC, ColorSpace); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + // Set up channels + nChannels = cmsChannelsOf(ColorSpace); + + // Creates a Pipeline with prelinearization step only + Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels); + if (Pipeline == NULL) goto Error; + + + // Copy tables to Pipeline + Lin = cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions); + if (Lin == NULL) goto Error; + + cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Lin); + + // Create tags + if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; + if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error; + if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error; + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + // Ok, done + return hICC; + +Error: + if (hICC) + cmsCloseProfile(hICC); + + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]) +{ + return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions); +} + +// Ink-limiting algorithm +// +// Sum = C + M + Y + K +// If Sum > InkLimit +// Ratio= 1 - (Sum - InkLimit) / (C + M + Y) +// if Ratio <0 +// Ratio=0 +// endif +// Else +// Ratio=1 +// endif +// +// C = Ratio * C +// M = Ratio * M +// Y = Ratio * Y +// K: Does not change + +static +int InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo; + cmsFloat64Number SumCMY, SumCMYK, Ratio; + + InkLimit = (InkLimit * 655.35); + + SumCMY = In[0] + In[1] + In[2]; + SumCMYK = SumCMY + In[3]; + + if (SumCMYK > InkLimit) { + + Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY); + if (Ratio < 0) + Ratio = 0; + } + else Ratio = 1; + + Out[0] = _cmsQuickSaturateWord(In[0] * Ratio); // C + Out[1] = _cmsQuickSaturateWord(In[1] * Ratio); // M + Out[2] = _cmsQuickSaturateWord(In[2] * Ratio); // Y + + Out[3] = In[3]; // K (untouched) + + return TRUE; +} + +// This is a devicelink operating in CMYK for ink-limiting + +cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, + cmsFloat64Number Limit) +{ + cmsHPROFILE hICC; + cmsPipeline* LUT; + cmsStage* CLUT; + int nChannels; + + if (ColorSpace != cmsSigCmykData) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported"); + return NULL; + } + + if (Limit < 0.0 || Limit > 400) { + + cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); + if (Limit < 0) Limit = 0; + if (Limit > 400) Limit = 400; + + } + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetProfileVersion(hICC, 4.2); + + cmsSetDeviceClass(hICC, cmsSigLinkClass); + cmsSetColorSpace(hICC, ColorSpace); + cmsSetPCS(hICC, ColorSpace); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Creates a Pipeline with 3D grid only + LUT = cmsPipelineAlloc(ContextID, 4, 4); + if (LUT == NULL) goto Error; + + + nChannels = cmsChannelsOf(ColorSpace); + + CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL); + if (CLUT == NULL) goto Error; + + if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; + + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)); + cmsPipelineInsertStage(LUT, cmsAT_END, CLUT); + cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)); + + // Create tags + if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; + + if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error; + if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error; + + // cmsPipeline is already on virtual profile + cmsPipelineFree(LUT); + + // Ok, done + return hICC; + +Error: + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hICC != NULL) + cmsCloseProfile(hICC); + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit) +{ + return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit); +} + + +// Creates a fake Lab identity. +cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + + hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileVersion(hProfile, 2.1); + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, cmsSigLabData); + cmsSetPCS(hProfile, cmsSigLabData); + + if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL; + + // An identity LUT is all we need + LUT = cmsPipelineAlloc(ContextID, 3, 3); + if (LUT == NULL) goto Error; + + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)); + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + cmsPipelineFree(LUT); + + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + + +cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint) +{ + return cmsCreateLab2ProfileTHR(NULL, WhitePoint); +} + + +// Creates a fake Lab V4 identity. +cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + + hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileVersion(hProfile, 4.2); + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, cmsSigLabData); + cmsSetPCS(hProfile, cmsSigLabData); + + if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error; + + // An empty LUTs is all we need + LUT = cmsPipelineAlloc(ContextID, 3, 3); + if (LUT == NULL) goto Error; + + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + cmsPipelineFree(LUT); + + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint) +{ + return cmsCreateLab4ProfileTHR(NULL, WhitePoint); +} + + +// Creates a fake XYZ identity +cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + + hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileVersion(hProfile, 4.2); + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, cmsSigXYZData); + cmsSetPCS(hProfile, cmsSigXYZData); + + if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error; + + // An identity LUT is all we need + LUT = cmsPipelineAlloc(ContextID, 3, 3); + if (LUT == NULL) goto Error; + + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + cmsPipelineFree(LUT); + + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + + +cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void) +{ + return cmsCreateXYZProfileTHR(NULL); +} + + +//sRGB Curves are defined by: +// +//If R’sRGB,G’sRGB, B’sRGB < 0.04045 +// +// R = R’sRGB / 12.92 +// G = G’sRGB / 12.92 +// B = B’sRGB / 12.92 +// +// +//else if R’sRGB,G’sRGB, B’sRGB >= 0.04045 +// +// R = ((R’sRGB + 0.055) / 1.055)^2.4 +// G = ((G’sRGB + 0.055) / 1.055)^2.4 +// B = ((B’sRGB + 0.055) / 1.055)^2.4 + +static +cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) +{ + cmsFloat64Number Parameters[5]; + + Parameters[0] = 2.4; + Parameters[1] = 1. / 1.055; + Parameters[2] = 0.055 / 1.055; + Parameters[3] = 1. / 12.92; + Parameters[4] = 0.04045; + + return cmsBuildParametricToneCurve(ContextID, 4, Parameters); +} + +// Create the ICC virtual profile for sRGB space +cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) +{ + cmsCIExyY D65; + cmsCIExyYTRIPLE Rec709Primaries = { + {0.6400, 0.3300, 1.0}, + {0.3000, 0.6000, 1.0}, + {0.1500, 0.0600, 1.0} + }; + cmsToneCurve* Gamma22[3]; + cmsHPROFILE hsRGB; + + cmsWhitePointFromTemp(&D65, 6504); + Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); + if (Gamma22[0] == NULL) return NULL; + + hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); + cmsFreeToneCurve(Gamma22[0]); + if (hsRGB == NULL) return NULL; + + if (!SetTextTags(hsRGB, L"sRGB built-in")) { + cmsCloseProfile(hsRGB); + return NULL; + } + + return hsRGB; +} + +cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) +{ + return cmsCreate_sRGBProfileTHR(NULL); +} + + + +typedef struct { + cmsFloat64Number Brightness; + cmsFloat64Number Contrast; + cmsFloat64Number Hue; + cmsFloat64Number Saturation; + cmsCIEXYZ WPsrc, WPdest; + +} BCHSWADJUSTS, *LPBCHSWADJUSTS; + + +static +int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + cmsCIELab LabIn, LabOut; + cmsCIELCh LChIn, LChOut; + cmsCIEXYZ XYZ; + LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; + + + cmsLabEncoded2Float(&LabIn, In); + + + cmsLab2LCh(&LChIn, &LabIn); + + // Do some adjusts on LCh + + LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; + LChOut.C = LChIn.C + bchsw -> Saturation; + LChOut.h = LChIn.h + bchsw -> Hue; + + + cmsLCh2Lab(&LabOut, &LChOut); + + // Move white point in Lab + + cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); + cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); + + // Back to encoded + + cmsFloat2LabEncoded(Out, &LabOut); + + return TRUE; +} + + +// Creates an abstract profile operating in Lab space for Brightness, +// contrast, Saturation and white point displacement + +cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, + int nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + int TempSrc, + int TempDest) +{ + cmsHPROFILE hICC; + cmsPipeline* Pipeline; + BCHSWADJUSTS bchsw; + cmsCIExyY WhitePnt; + cmsStage* CLUT; + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; + + + bchsw.Brightness = Bright; + bchsw.Contrast = Contrast; + bchsw.Hue = Hue; + bchsw.Saturation = Saturation; + + cmsWhitePointFromTemp(&WhitePnt, TempSrc ); + cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + + cmsWhitePointFromTemp(&WhitePnt, TempDest); + cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + + cmsSetDeviceClass(hICC, cmsSigAbstractClass); + cmsSetColorSpace(hICC, cmsSigLabData); + cmsSetPCS(hICC, cmsSigLabData); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Creates a Pipeline with 3D grid only + Pipeline = cmsPipelineAlloc(ContextID, 3, 3); + if (Pipeline == NULL) { + cmsCloseProfile(hICC); + return NULL; + } + + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; + CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); + if (CLUT == NULL) return NULL; + + + if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { + + // Shouldn't reach here + cmsPipelineFree(Pipeline); + cmsCloseProfile(hICC); + return NULL; + } + + cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT); + + // Create tags + + if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; + + cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); + + cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + // Ok, done + return hICC; +} + + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + int TempSrc, + int TempDest) +{ + return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest); +} + + +// Creates a fake NULL profile. This profile return 1 channel as always 0. +// Is useful only for gamut checking tricks +cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + cmsStage* PostLin; + cmsToneCurve* EmptyTab; + cmsUInt16Number Zero[2] = { 0, 0 }; + + hProfile = cmsCreateProfilePlaceholder(ContextID); + if (!hProfile) // can't allocate + return NULL; + + cmsSetProfileVersion(hProfile, 4.2); + + if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; + + + + cmsSetDeviceClass(hProfile, cmsSigOutputClass); + cmsSetColorSpace(hProfile, cmsSigGrayData); + cmsSetPCS(hProfile, cmsSigLabData); + + // An empty LUTs is all we need + LUT = cmsPipelineAlloc(ContextID, 1, 1); + if (LUT == NULL) goto Error; + + EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); + PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab); + cmsFreeToneCurve(EmptyTab); + + cmsPipelineInsertStage(LUT, cmsAT_END, PostLin); + + if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; + + cmsPipelineFree(LUT); + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void) +{ + return cmsCreateNULLProfileTHR(NULL); +} + + +static +int IsPCS(cmsColorSpaceSignature ColorSpace) +{ + return (ColorSpace == cmsSigXYZData || + ColorSpace == cmsSigLabData); +} + + +static +void FixColorSpaces(cmsHPROFILE hProfile, + cmsColorSpaceSignature ColorSpace, + cmsColorSpaceSignature PCS, + cmsUInt32Number dwFlags) +{ + if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) { + + if (IsPCS(ColorSpace) && IsPCS(PCS)) { + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + return; + } + + if (IsPCS(ColorSpace) && !IsPCS(PCS)) { + + cmsSetDeviceClass(hProfile, cmsSigOutputClass); + cmsSetPCS(hProfile, ColorSpace); + cmsSetColorSpace(hProfile, PCS); + return; + } + + if (IsPCS(PCS) && !IsPCS(ColorSpace)) { + + cmsSetDeviceClass(hProfile, cmsSigInputClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + return; + } + } + + cmsSetDeviceClass(hProfile, cmsSigLinkClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); +} + + + +// This function creates a named color profile dumping all the contents of transform to a single profile +// In this way, LittleCMS may be used to "group" several named color databases into a single profile. +// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this +// is the normal PCS for named color profiles. +static +cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) +{ + _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; + cmsHPROFILE hICC = NULL; + int i, nColors; + cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL; + + // Create an empty placeholder + hICC = cmsCreateProfilePlaceholder(v->ContextID); + if (hICC == NULL) return NULL; + + // Critical information + cmsSetDeviceClass(hICC, cmsSigNamedColorClass); + cmsSetColorSpace(hICC, v ->ExitColorSpace); + cmsSetPCS(hICC, cmsSigLabData); + + // Tag profile with information + if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; + + Original = cmsGetNamedColorList(xform); + if (Original == NULL) goto Error; + + nColors = cmsNamedColorCount(Original); + nc2 = cmsDupNamedColorList(Original); + if (nc2 == NULL) goto Error; + + // Colorant count now depends on the output space + nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut); + + // Apply the transfor to colorants. + for (i=0; i < nColors; i++) { + cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); + } + + if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error; + cmsFreeNamedColorList(nc2); + + return hICC; + +Error: + if (hICC != NULL) cmsCloseProfile(hICC); + return NULL; +} + + +// This structure holds information about which MPU can be stored on a profile based on the version + +typedef struct { + cmsBool IsV4; // Is a V4 tag? + cmsTagSignature RequiredTag; // Set to 0 for both types + cmsTagTypeSignature LutType; // The LUT type + int nTypes; // Number of types (up to 5) + cmsStageSignature MpeTypes[5]; // 5 is the maximum number + +} cmsAllowedLUT; + +static const cmsAllowedLUT AllowedLUTTypes[] = { + + { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, + { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, + { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, + { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} +}; + +#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT)) + +// Check a single entry +static +cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) +{ + cmsStage* mpe; + int n; + + for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { + + if (n > Tab ->nTypes) return FALSE; + if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; + } + + return (n == Tab ->nTypes); +} + + +static +const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag) +{ + int n; + + for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) { + + const cmsAllowedLUT* Tab = AllowedLUTTypes + n; + + if (IsV4 ^ Tab -> IsV4) continue; + if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue; + + if (CheckOne(Tab, Lut)) return Tab; + } + + return NULL; +} + + +// Does convert a transform into a device link profile +cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) +{ + cmsHPROFILE hProfile = NULL; + cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut; + cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut; + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + cmsPipeline* LUT = NULL; + cmsStage* mpe; + cmsContext ContextID = cmsGetTransformContextID(hTransform); + const cmsAllowedLUT* AllowedLUT; + cmsTagSignature DestinationTag; + + _cmsAssert(hTransform != NULL); + + // Get the first mpe to check for named color + mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); + + // Check if is a named color transform + if (mpe != NULL) { + + if (cmsStageType(mpe) == cmsSigNamedColorElemType) { + return CreateNamedColorDevicelink(hTransform); + } + } + + // First thing to do is to get a copy of the transformation + LUT = cmsPipelineDup(xform ->Lut); + if (LUT == NULL) return NULL; + + // Time to fix the Lab2/Lab4 issue. + if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { + + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)); + } + + // On the output side too + if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { + + cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)); + } + + + hProfile = cmsCreateProfilePlaceholder(ContextID); + if (!hProfile) goto Error; // can't allocate + + cmsSetProfileVersion(hProfile, Version); + + FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); + + // Optimize the LUT and precalculate a devicelink + + ChansIn = cmsChannelsOf(xform -> EntryColorSpace); + ChansOut = cmsChannelsOf(xform -> ExitColorSpace); + + ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace); + ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace); + + FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); + FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); + + + if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) + DestinationTag = cmsSigBToA0Tag; + else + DestinationTag = cmsSigAToB0Tag; + + // Check if the profile/version can store the result + if (dwFlags & cmsFLAGS_FORCE_CLUT) + AllowedLUT = NULL; + else + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + + if (AllowedLUT == NULL) { + + // Try to optimize + _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + + } + + // If no way, then force CLUT that for sure can be written + if (AllowedLUT == NULL) { + + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + + // Put identity curves if needed + if (cmsPipelineStageCount(LUT) == 1) { + + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)); + cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)); + } + + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + } + + // Somethings is wrong... + if (AllowedLUT == NULL) { + goto Error; + } + + + if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) + cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE); + + // Tag profile with information + if (!SetTextTags(hProfile, L"devicelink")) goto Error; + + // Store result + if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error; + + + if (xform -> InputColorant != NULL) { + if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error; + } + + if (xform -> OutputColorant != NULL) { + if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; + } + + if (xform ->Sequence != NULL) { + if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; + } + + cmsPipelineFree(LUT); + return hProfile; + +Error: + if (LUT != NULL) cmsPipelineFree(LUT); + cmsCloseProfile(hProfile); + return NULL; +} diff --git a/thirdparty/liblcms2/src/cmswtpnt.c b/thirdparty/liblcms2/src/cmswtpnt.c new file mode 100644 index 00000000..6319984c --- /dev/null +++ b/thirdparty/liblcms2/src/cmswtpnt.c @@ -0,0 +1,351 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// D50 - Widely used +const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void) +{ + static cmsCIEXYZ D50XYZ = {cmsD50X, cmsD50Y, cmsD50Z}; + + return &D50XYZ; +} + +const cmsCIExyY* CMSEXPORT cmsD50_xyY(void) +{ + static cmsCIExyY D50xyY; + + cmsXYZ2xyY(&D50xyY, cmsD50_XYZ()); + + return &D50xyY; +} + +// Obtains WhitePoint from Temperature +cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK) +{ + cmsFloat64Number x, y; + cmsFloat64Number T, T2, T3; + // cmsFloat64Number M1, M2; + + _cmsAssert(WhitePoint != NULL); + + T = TempK; + T2 = T*T; // Square + T3 = T2*T; // Cube + + // For correlated color temperature (T) between 4000K and 7000K: + + if (T >= 4000. && T <= 7000.) + { + x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; + } + else + // or for correlated color temperature (T) between 7000K and 25000K: + + if (T > 7000.0 && T <= 25000.0) + { + x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); + return FALSE; + } + + // Obtain y(x) + + y = -3.000*(x*x) + 2.870*x - 0.275; + + // wave factors (not used, but here for futures extensions) + + // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); + // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); + + WhitePoint -> x = x; + WhitePoint -> y = y; + WhitePoint -> Y = 1.0; + + return TRUE; +} + + + +typedef struct { + + cmsFloat64Number mirek; // temp (in microreciprocal kelvin) + cmsFloat64Number ut; // u coord of intersection w/ blackbody locus + cmsFloat64Number vt; // v coord of intersection w/ blackbody locus + cmsFloat64Number tt; // slope of ISOTEMPERATURE. line + + } ISOTEMPERATURE; + +static ISOTEMPERATURE isotempdata[] = { +// {Mirek, Ut, Vt, Tt } + {0, 0.18006, 0.26352, -0.24341}, + {10, 0.18066, 0.26589, -0.25479}, + {20, 0.18133, 0.26846, -0.26876}, + {30, 0.18208, 0.27119, -0.28539}, + {40, 0.18293, 0.27407, -0.30470}, + {50, 0.18388, 0.27709, -0.32675}, + {60, 0.18494, 0.28021, -0.35156}, + {70, 0.18611, 0.28342, -0.37915}, + {80, 0.18740, 0.28668, -0.40955}, + {90, 0.18880, 0.28997, -0.44278}, + {100, 0.19032, 0.29326, -0.47888}, + {125, 0.19462, 0.30141, -0.58204}, + {150, 0.19962, 0.30921, -0.70471}, + {175, 0.20525, 0.31647, -0.84901}, + {200, 0.21142, 0.32312, -1.0182 }, + {225, 0.21807, 0.32909, -1.2168 }, + {250, 0.22511, 0.33439, -1.4512 }, + {275, 0.23247, 0.33904, -1.7298 }, + {300, 0.24010, 0.34308, -2.0637 }, + {325, 0.24702, 0.34655, -2.4681 }, + {350, 0.25591, 0.34951, -2.9641 }, + {375, 0.26400, 0.35200, -3.5814 }, + {400, 0.27218, 0.35407, -4.3633 }, + {425, 0.28039, 0.35577, -5.3762 }, + {450, 0.28863, 0.35714, -6.7262 }, + {475, 0.29685, 0.35823, -8.5955 }, + {500, 0.30505, 0.35907, -11.324 }, + {525, 0.31320, 0.35968, -15.628 }, + {550, 0.32129, 0.36011, -23.325 }, + {575, 0.32931, 0.36038, -40.770 }, + {600, 0.33724, 0.36051, -116.45 } +}; + +#define NISO sizeof(isotempdata)/sizeof(ISOTEMPERATURE) + + +// Robertson's method +cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint) +{ + int j; + cmsFloat64Number us,vs; + cmsFloat64Number uj,vj,tj,di,dj,mi,mj; + cmsFloat64Number xs, ys; + + _cmsAssert(WhitePoint != NULL); + _cmsAssert(TempK != NULL); + + di = mi = 0; + xs = WhitePoint -> x; + ys = WhitePoint -> y; + + // convert (x,y) to CIE 1960 (u,WhitePoint) + + us = (2*xs) / (-xs + 6*ys + 1.5); + vs = (3*ys) / (-xs + 6*ys + 1.5); + + + for (j=0; j < NISO; j++) { + + uj = isotempdata[j].ut; + vj = isotempdata[j].vt; + tj = isotempdata[j].tt; + mj = isotempdata[j].mirek; + + dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj); + + if ((j != 0) && (di/dj < 0.0)) { + + // Found a match + *TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); + return TRUE; + } + + di = dj; + mi = mj; + } + + // Not found + return FALSE; +} + + +// Compute chromatic adaptation matrix using Chad as cone matrix + +static +cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, + const cmsCIEXYZ* SourceWhitePoint, + const cmsCIEXYZ* DestWhitePoint, + const cmsMAT3* Chad) + +{ + + cmsMAT3 Chad_Inv; + cmsVEC3 ConeSourceXYZ, ConeSourceRGB; + cmsVEC3 ConeDestXYZ, ConeDestRGB; + cmsMAT3 Cone, Tmp; + + + Tmp = *Chad; + if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE; + + _cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X, + SourceWhitePoint -> Y, + SourceWhitePoint -> Z); + + _cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X, + DestWhitePoint -> Y, + DestWhitePoint -> Z); + + _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); + _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); + + // Build matrix + _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); + _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); + _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); + + + // Normalize + _cmsMAT3per(&Tmp, &Cone, Chad); + _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); + + return TRUE; +} + +// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll +// The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed +cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll) +{ + cmsMAT3 LamRigg = {{ // Bradford matrix + {{ 0.8951, 0.2664, -0.1614 }}, + {{ -0.7502, 1.7135, 0.0367 }}, + {{ 0.0389, -0.0685, 1.0296 }} + }}; + + if (ConeMatrix == NULL) + ConeMatrix = &LamRigg; + + return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix); +} + +// Same as anterior, but assuming D50 destination. White point is given in xyY +static +cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) +{ + cmsCIEXYZ Dn; + cmsMAT3 Bradford; + cmsMAT3 Tmp; + + cmsxyY2XYZ(&Dn, SourceWhitePt); + + if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE; + + Tmp = *r; + _cmsMAT3per(r, &Bradford, &Tmp); + + return TRUE; +} + +// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ +// This is just an approximation, I am not handling all the non-linear +// aspects of the RGB to XYZ process, and assumming that the gamma correction +// has transitive property in the tranformation chain. +// +// the alghoritm: +// +// - First I build the absolute conversion matrix using +// primaries in XYZ. This matrix is next inverted +// - Then I eval the source white point across this matrix +// obtaining the coeficients of the transformation +// - Then, I apply these coeficients to the original matrix +// +cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) +{ + cmsVEC3 WhitePoint, Coef; + cmsMAT3 Result, Primaries; + cmsFloat64Number xn, yn; + cmsFloat64Number xr, yr; + cmsFloat64Number xg, yg; + cmsFloat64Number xb, yb; + + xn = WhitePt -> x; + yn = WhitePt -> y; + xr = Primrs -> Red.x; + yr = Primrs -> Red.y; + xg = Primrs -> Green.x; + yg = Primrs -> Green.y; + xb = Primrs -> Blue.x; + yb = Primrs -> Blue.y; + + // Build Primaries matrix + _cmsVEC3init(&Primaries.v[0], xr, xg, xb); + _cmsVEC3init(&Primaries.v[1], yr, yg, yb); + _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); + + + // Result = Primaries ^ (-1) inverse matrix + if (!_cmsMAT3inverse(&Primaries, &Result)) + return FALSE; + + + _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); + + // Across inverse primaries ... + _cmsMAT3eval(&Coef, &Result, &WhitePoint); + + // Give us the Coefs, then I build transformation matrix + _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); + _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); + _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); + + + return _cmsAdaptMatrixToD50(r, WhitePt); + +} + + +// Adapts a color to a given illuminant. Original color is expected to have +// a SourceWhitePt white point. +cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, + const cmsCIEXYZ* SourceWhitePt, + const cmsCIEXYZ* Illuminant, + const cmsCIEXYZ* Value) +{ + cmsMAT3 Bradford; + cmsVEC3 In, Out; + + _cmsAssert(Result != NULL); + _cmsAssert(SourceWhitePt != NULL); + _cmsAssert(Illuminant != NULL); + _cmsAssert(Value != NULL); + + if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE; + + _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z); + _cmsMAT3eval(&Out, &Bradford, &In); + + Result -> X = Out.n[0]; + Result -> Y = Out.n[1]; + Result -> Z = Out.n[2]; + + return TRUE; +} + + diff --git a/thirdparty/liblcms2/src/cmsxform.c b/thirdparty/liblcms2/src/cmsxform.c new file mode 100644 index 00000000..7f5cc947 --- /dev/null +++ b/thirdparty/liblcms2/src/cmsxform.c @@ -0,0 +1,809 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Transformations stuff +// ----------------------------------------------------------------------- + +// Alarm codes for 16-bit transformations, because the fixed range of containers there are +// no values left to mark out of gamut. volatile is C99 per 6.2.5 +static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS]; +static volatile cmsFloat64Number GlobalAdaptationState = 0; + +// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine +cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) +{ + cmsFloat64Number OldVal = GlobalAdaptationState; + + if (d >= 0) + GlobalAdaptationState = d; + + return OldVal; +} + +// Alarm codes are always global +void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +{ + int i; + + _cmsAssert(NewAlarm != NULL); + + for (i=0; i < cmsMAXCHANNELS; i++) + Alarm[i] = NewAlarm[i]; +} + +// You can get the codes cas well +void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) +{ + int i; + + _cmsAssert(OldAlarm != NULL); + + for (i=0; i < cmsMAXCHANNELS; i++) + OldAlarm[i] = Alarm[i]; +} + +// Get rid of transform resources +void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform; + + _cmsAssert(p != NULL); + + if (p -> GamutCheck) + cmsPipelineFree(p -> GamutCheck); + + if (p -> Lut) + cmsPipelineFree(p -> Lut); + + if (p ->InputColorant) + cmsFreeNamedColorList(p ->InputColorant); + + if (p -> OutputColorant) + cmsFreeNamedColorList(p ->OutputColorant); + + if (p ->Sequence) + cmsFreeProfileSequenceDescription(p ->Sequence); + + LCMS_FREE_LOCK(&p->rwlock); + _cmsFree(p ->ContextID, (void *) p); +} + +// Apply transform +void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + + p -> xform(p, InputBuffer, OutputBuffer, Size); +} + + +// Transform routines ---------------------------------------------------------------------------------------------------------- + +// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check. +// Note that because extended range, we can use a -1.0 value for out of gamut in this case. +static +void FloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, cmsUInt32Number Size) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS]; + cmsFloat32Number OutOfGamut; + cmsUInt32Number i, j; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + + for (i=0; i < Size; i++) { + + accum = p -> FromInputFloat(p, fIn, accum, Size); + + // Any gamut chack to do? + if (p ->GamutCheck != NULL) { + + // Evaluate gamut marker. + cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck); + + // Is current color out of gamut? + if (OutOfGamut > 0.0) { + + // Certainly, out of gamut + for (j=0; j < cmsMAXCHANNELS; j++) + fOut[j] = -1.0; + + } + else { + // No, proceed normally + cmsPipelineEvalFloat(fIn, fOut, p -> Lut); + } + } + else { + + // No gamut check at all + cmsPipelineEvalFloat(fIn, fOut, p -> Lut); + } + + // Back to asked representation + output = p -> ToOutputFloat(p, fOut, output, Size); + } +} + +// 16 bit precision ----------------------------------------------------------------------------------------------------------- + +// Null transformation, only applies formatters. No caché +static +void NullXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, cmsUInt32Number Size) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; // Buffer len + + for (i=0; i < n; i++) { + + accum = p -> FromInput(p, wIn, accum, Size); + output = p -> ToOutput(p, wIn, output, Size); + } +} + + +// No gamut check, no cache, 16 bits +static +void PrecalculatedXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, cmsUInt32Number Size) +{ + register cmsUInt8Number* accum; + register cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; + + for (i=0; i < n; i++) { + + accum = p -> FromInput(p, wIn, accum, Size); + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + output = p -> ToOutput(p, wOut, output, Size); + } +} + + +// Auxiliar: Handle precalculated gamut check +static +void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, + const cmsUInt16Number wIn[], + cmsUInt16Number wOut[]) +{ + cmsUInt16Number wOutOfGamut; + + p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data); + if (wOutOfGamut >= 1) { + + cmsUInt16Number i; + + for (i=0; i < p ->Lut->OutputChannels; i++) + wOut[i] = Alarm[i]; + } + else + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); +} + +// Gamut check, No caché, 16 bits. +static +void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, + const void* in, + void* out, cmsUInt32Number Size) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; // Buffer len + + for (i=0; i < n; i++) { + + accum = p -> FromInput(p, wIn, accum, Size); + TransformOnePixelWithGamutCheck(p, wIn, wOut); + output = p -> ToOutput(p, wOut, output, Size); + } +} + + +// No gamut check, Caché, 16 bits, +static +void CachedXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, cmsUInt32Number Size) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS]; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; // Buffer len + + // Empty buffers for quick memcmp + memset(wIn, 0, sizeof(wIn)); + memset(wOut, 0, sizeof(wOut)); + + + LCMS_READ_LOCK(&p ->rwlock); + memmove(CacheIn, p ->CacheIn, sizeof(CacheIn)); + memmove(CacheOut, p ->CacheOut, sizeof(CacheOut)); + LCMS_UNLOCK(&p ->rwlock); + + for (i=0; i < n; i++) { + + accum = p -> FromInput(p, wIn, accum, Size); + + if (memcmp(wIn, CacheIn, sizeof(CacheIn)) == 0) { + + memmove(wOut, CacheOut, sizeof(CacheOut)); + } + else { + + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + + memmove(CacheIn, wIn, sizeof(CacheIn)); + memmove(CacheOut, wOut, sizeof(CacheOut)); + } + + output = p -> ToOutput(p, wOut, output, Size); + } + + + LCMS_WRITE_LOCK(&p ->rwlock); + memmove(p->CacheIn, CacheIn, sizeof(CacheIn)); + memmove(p->CacheOut, CacheOut, sizeof(CacheOut)); + LCMS_UNLOCK(&p ->rwlock); +} + + +// All those nice features together +static +void CachedXFORMGamutCheck(_cmsTRANSFORM* p, + const void* in, + void* out, cmsUInt32Number Size) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS]; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; // Buffer len + + // Empty buffers for quick memcmp + memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + + LCMS_READ_LOCK(&p ->rwlock); + memmove(CacheIn, p ->CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + memmove(CacheOut, p ->CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); + + + for (i=0; i < n; i++) { + + accum = p -> FromInput(p, wIn, accum, Size); + + if (memcmp(wIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS) == 0) { + memmove(wOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + } + else { + TransformOnePixelWithGamutCheck(p, wIn, wOut); + memmove(CacheIn, wIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + memmove(CacheOut, wOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + } + + output = p -> ToOutput(p, wOut, output, Size); + } + + LCMS_WRITE_LOCK(&p ->rwlock); + memmove(p->CacheIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + memmove(p->CacheOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); +} + + + + +// Allocate transform struct and set it to defaults +static +_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags) +{ + // Allocate needed memory + _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); + if (!p) return NULL; + + // Check whatever this is a true floating point transform + if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) { + + // Get formatter function always return a valid union, but the contents of this union may be NULL. + p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + + if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + _cmsFree(ContextID, p); + return NULL; + } + + // Float transforms don't use caché, always are non-NULL + p ->xform = FloatXFORM; + } + else { + + if (InputFormat == 0 && OutputFormat == 0) { + p ->FromInput = p ->ToOutput = NULL; + } + else { + + int BytesPerPixelInput; + + p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + + + if (p ->FromInput == NULL || p ->ToOutput == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + _cmsFree(ContextID, p); + return NULL; + } + + BytesPerPixelInput = T_BYTES(p ->InputFormat); + if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) + dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + + } + + if (dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullXFORM; + } + else { + if (dwFlags & cmsFLAGS_NOCACHE) { + + if (dwFlags & cmsFLAGS_GAMUTCHECK) + p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché + else + p ->xform = PrecalculatedXFORM; // No caché, no gamut check + } + else { + + if (dwFlags & cmsFLAGS_GAMUTCHECK) + p ->xform = CachedXFORMGamutCheck; // Gamut check, caché + else + p ->xform = CachedXFORM; // No gamut check, caché + + } + } + } + + + // Create a mutex for shared memory + LCMS_CREATE_LOCK(&p->rwlock); + + p ->InputFormat = InputFormat; + p ->OutputFormat = OutputFormat; + p ->dwOriginalFlags = dwFlags; + p ->ContextID = ContextID; + return p; +} + +static +cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output) +{ + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut; + cmsColorSpaceSignature PostColorSpace; + int i; + + if (hProfiles[0] == NULL) return FALSE; + + *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]); + + for (i=0; i < nProfiles; i++) { + + cmsHPROFILE hProfile = hProfiles[i]; + + int lIsInput = (PostColorSpace != cmsSigXYZData) && + (PostColorSpace != cmsSigLabData); + + if (hProfile == NULL) return FALSE; + + if (lIsInput) { + + ColorSpaceIn = cmsGetColorSpace(hProfile); + ColorSpaceOut = cmsGetPCS(hProfile); + } + else { + + ColorSpaceIn = cmsGetPCS(hProfile); + ColorSpaceOut = cmsGetColorSpace(hProfile); + } + + PostColorSpace = ColorSpaceOut; + } + + *Output = PostColorSpace; + + return TRUE; +} + +// Check colorspace +static +cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat) +{ + int Space1 = T_COLORSPACE(dwFormat); + int Space2 = _cmsLCMScolorSpace(Check); + + if (Space1 == PT_ANY) return TRUE; + if (Space1 == Space2) return TRUE; + + if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE; + if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE; + + return FALSE; +} + +// ---------------------------------------------------------------------------------------------------------------- + +// New to lcms 2.0 -- have all parameters available. +cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, + cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsHPROFILE hGamutProfile, + cmsUInt32Number nGamutPCSposition, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number dwFlags) +{ + _cmsTRANSFORM* xform; + cmsBool FloatTransform; + cmsColorSpaceSignature EntryColorSpace; + cmsColorSpaceSignature ExitColorSpace; + cmsPipeline* Lut; + cmsUInt32Number LastIntent = Intents[nProfiles-1]; + + // If gamut check is requested, make sure we have a gamut profile + if (dwFlags & cmsFLAGS_GAMUTCHECK) { + if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK; + } + + // On floating point transforms, inhibit optimizations + FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)); + + if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat)) + dwFlags |= cmsFLAGS_NOCACHE; + + // Mark entry/exit spaces + if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) { + cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform"); + return NULL; + } + + // Check if proper colorspaces + if (!IsProperColorSpace(EntryColorSpace, InputFormat)) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform"); + return NULL; + } + + if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform"); + return NULL; + } + + // Create a pipeline with all transformations + Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (Lut == NULL) { + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles"); + return NULL; + } + + // Optimize the LUT if possible + _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); + + + // All seems ok + xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags); + if (xform == NULL) { + cmsPipelineFree(Lut); + return NULL; + } + + // Keep values + xform ->EntryColorSpace = EntryColorSpace; + xform ->ExitColorSpace = ExitColorSpace; + xform ->Lut = Lut; + + + // Create a gamut check LUT if requested + if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) + xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles, + BPC, Intents, + AdaptationStates, + nGamutPCSposition, + hGamutProfile); + + + // Try to read input and output colorant table + if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) { + + // Input table can only come in this way. + xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag)); + } + + // Output is a little bit more complex. + if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) { + + // This tag may exist only on devicelink profiles. + if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) { + + // It may be NULL if error + xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)); + } + + } else { + + if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) { + + xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)); + } + } + + // Store the sequence of profiles + if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) { + xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles); + } + else + xform ->Sequence = NULL; + + // If this is a cached transform, init first value, which is zero (16 bits only) + if (!(dwFlags & cmsFLAGS_NOCACHE)) { + + memset(&xform ->CacheIn, 0, sizeof(xform ->CacheIn)); + + if (xform ->GamutCheck != NULL) { + TransformOnePixelWithGamutCheck(xform, xform ->CacheIn, xform->CacheOut); + } + else { + + xform ->Lut ->Eval16Fn(xform ->CacheIn, xform->CacheOut, xform -> Lut->Data); + } + + } + + return (cmsHTRANSFORM) xform; +} + +// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes. + +cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsBool BPC[256]; + cmsUInt32Number Intents[256]; + cmsFloat64Number AdaptationStates[256]; + + if (nProfiles <= 0 || nProfiles > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles); + return NULL; + } + + for (i=0; i < nProfiles; i++) { + BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; + Intents[i] = Intent; + AdaptationStates[i] = GlobalAdaptationState; + } + + + return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags); +} + + + +cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + + if (nProfiles <= 0 || nProfiles > 255) { + cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles); + return NULL; + } + + return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]), + hProfiles, + nProfiles, + InputFormat, + OutputFormat, + Intent, + dwFlags); +} + +cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID, + cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + + cmsHPROFILE hArray[2]; + + hArray[0] = Input; + hArray[1] = Output; + + return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags); +} + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags); +} + + +cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, + cmsHPROFILE InputProfile, + cmsUInt32Number InputFormat, + cmsHPROFILE OutputProfile, + cmsUInt32Number OutputFormat, + cmsHPROFILE ProofingProfile, + cmsUInt32Number nIntent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags) +{ + cmsHPROFILE hArray[4]; + cmsUInt32Number Intents[4]; + cmsBool BPC[4]; + cmsFloat64Number Adaptation[4]; + cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE; + + + hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile; + Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; + BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; + + Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState; + + if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) + return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); + + return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation, + ProofingProfile, 1, InputFormat, OutputFormat, dwFlags); + +} + + +cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, + cmsUInt32Number InputFormat, + cmsHPROFILE OutputProfile, + cmsUInt32Number OutputFormat, + cmsHPROFILE ProofingProfile, + cmsUInt32Number nIntent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags) +{ + return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile), + InputProfile, + InputFormat, + OutputProfile, + OutputFormat, + ProofingProfile, + nIntent, + ProofingIntent, + dwFlags); +} + + +// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed +cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + + if (xform == NULL) return NULL; + return xform -> ContextID; +} + + + +// For backwards compatibility +cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat) +{ + + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + cmsFormatter16 FromInput, ToOutput; + cmsUInt32Number BytesPerPixelInput; + + // We only can afford to change formatters if previous transform is at least 16 bits + BytesPerPixelInput = T_BYTES(xform ->InputFormat); + if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) { + + cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision"); + return FALSE; + } + + FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + + if (FromInput == NULL || ToOutput == NULL) { + + cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + return FALSE; + } + + xform ->InputFormat = InputFormat; + xform ->OutputFormat = OutputFormat; + xform ->FromInput = FromInput; + xform ->ToOutput = ToOutput; + return TRUE; +} diff --git a/thirdparty/liblcms2/src/lcms2.def b/thirdparty/liblcms2/src/lcms2.def new file mode 100644 index 00000000..d4075021 --- /dev/null +++ b/thirdparty/liblcms2/src/lcms2.def @@ -0,0 +1,300 @@ +LIBRARY LCMS2.DLL + +EXPORTS + +_cms15Fixed16toDouble = _cms15Fixed16toDouble +_cms8Fixed8toDouble = _cms8Fixed8toDouble +cmsAdaptToIlluminant = cmsAdaptToIlluminant +_cmsAdjustEndianess16 = _cmsAdjustEndianess16 +_cmsAdjustEndianess32 = _cmsAdjustEndianess32 +_cmsAdjustEndianess64 = _cmsAdjustEndianess64 +cmsAllocNamedColorList = cmsAllocNamedColorList +cmsAllocProfileSequenceDescription = cmsAllocProfileSequenceDescription +cmsAppendNamedColor = cmsAppendNamedColor +cmsBFDdeltaE = cmsBFDdeltaE +cmsBuildGamma = cmsBuildGamma +cmsBuildParametricToneCurve = cmsBuildParametricToneCurve +cmsBuildSegmentedToneCurve = cmsBuildSegmentedToneCurve +cmsBuildTabulatedToneCurve16 = cmsBuildTabulatedToneCurve16 +cmsBuildTabulatedToneCurveFloat = cmsBuildTabulatedToneCurveFloat +_cmsCalloc = _cmsCalloc +cmsChannelsOf = cmsChannelsOf +cmsCIE2000DeltaE = cmsCIE2000DeltaE +cmsCIE94DeltaE = cmsCIE94DeltaE +cmsCIECAM02Done = cmsCIECAM02Done +cmsCIECAM02Forward = cmsCIECAM02Forward +cmsCIECAM02Init = cmsCIECAM02Init +cmsCIECAM02Reverse = cmsCIECAM02Reverse +cmsCloseIOhandler = cmsCloseIOhandler +cmsCloseProfile = cmsCloseProfile +cmsCMCdeltaE = cmsCMCdeltaE +cmsCreate_sRGBProfile = cmsCreate_sRGBProfile +cmsCreate_sRGBProfileTHR = cmsCreate_sRGBProfileTHR +cmsCreateBCHSWabstractProfile = cmsCreateBCHSWabstractProfile +cmsCreateBCHSWabstractProfileTHR = cmsCreateBCHSWabstractProfileTHR +cmsCreateExtendedTransform = cmsCreateExtendedTransform +cmsCreateGrayProfile = cmsCreateGrayProfile +cmsCreateGrayProfileTHR = cmsCreateGrayProfileTHR +cmsCreateInkLimitingDeviceLink = cmsCreateInkLimitingDeviceLink +cmsCreateInkLimitingDeviceLinkTHR = cmsCreateInkLimitingDeviceLinkTHR +cmsCreateLab2Profile = cmsCreateLab2Profile +cmsCreateLab2ProfileTHR = cmsCreateLab2ProfileTHR +cmsCreateLab4Profile = cmsCreateLab4Profile +cmsCreateLab4ProfileTHR = cmsCreateLab4ProfileTHR +cmsCreateLinearizationDeviceLink = cmsCreateLinearizationDeviceLink +cmsCreateLinearizationDeviceLinkTHR = cmsCreateLinearizationDeviceLinkTHR +cmsCreateMultiprofileTransform = cmsCreateMultiprofileTransform +cmsCreateMultiprofileTransformTHR = cmsCreateMultiprofileTransformTHR +cmsCreateNULLProfile = cmsCreateNULLProfile +cmsCreateNULLProfileTHR = cmsCreateNULLProfileTHR +cmsCreateProfilePlaceholder = cmsCreateProfilePlaceholder +cmsCreateProofingTransform = cmsCreateProofingTransform +cmsCreateProofingTransformTHR = cmsCreateProofingTransformTHR +cmsCreateRGBProfile = cmsCreateRGBProfile +cmsCreateRGBProfileTHR = cmsCreateRGBProfileTHR +cmsCreateTransform = cmsCreateTransform +cmsCreateTransformTHR = cmsCreateTransformTHR +cmsCreateXYZProfile = cmsCreateXYZProfile +cmsCreateXYZProfileTHR = cmsCreateXYZProfileTHR +cmsD50_xyY = cmsD50_xyY +cmsD50_XYZ = cmsD50_XYZ +_cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber +_cmsDefaultICCintents = _cmsDefaultICCintents +cmsDeleteTransform = cmsDeleteTransform +cmsDeltaE = cmsDeltaE +cmsDetectBlackPoint = cmsDetectBlackPoint +cmsDetectTAC = cmsDetectTAC +cmsDesaturateLab = cmsDesaturateLab +cmsDoTransform = cmsDoTransform +_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16 +_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8 +_cmsDupMem = _cmsDupMem +cmsDupNamedColorList = cmsDupNamedColorList +cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription +cmsDupToneCurve = cmsDupToneCurve +_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber +cmsEstimateGamma = cmsEstimateGamma +cmsEvalToneCurve16 = cmsEvalToneCurve16 +cmsEvalToneCurveFloat = cmsEvalToneCurveFloat +cmsfilelength = cmsfilelength +cmsFloat2LabEncoded = cmsFloat2LabEncoded +cmsFloat2LabEncodedV2 = cmsFloat2LabEncodedV2 +cmsFloat2XYZEncoded = cmsFloat2XYZEncoded +cmsFormatterForColorspaceOfProfile = cmsFormatterForColorspaceOfProfile +cmsFormatterForPCSOfProfile = cmsFormatterForPCSOfProfile +_cmsFree = _cmsFree +cmsFreeNamedColorList = cmsFreeNamedColorList +cmsFreeProfileSequenceDescription = cmsFreeProfileSequenceDescription +cmsFreeToneCurve = cmsFreeToneCurve +cmsFreeToneCurveTriple = cmsFreeToneCurveTriple +cmsGBDAlloc = cmsGBDAlloc +cmsGBDFree = cmsGBDFree +cmsGDBAddPoint = cmsGDBAddPoint +cmsGDBCheckPoint = cmsGDBCheckPoint +cmsGDBCompute = cmsGDBCompute +cmsGetAlarmCodes = cmsGetAlarmCodes +cmsGetColorSpace = cmsGetColorSpace +cmsGetDeviceClass = cmsGetDeviceClass +cmsGetEncodedICCversion = cmsGetEncodedICCversion +cmsGetHeaderAttributes = cmsGetHeaderAttributes +cmsGetHeaderCreationDateTime = cmsGetHeaderCreationDateTime +cmsGetHeaderFlags = cmsGetHeaderFlags +cmsGetHeaderManufacturer = cmsGetHeaderManufacturer +cmsGetHeaderModel = cmsGetHeaderModel +cmsGetHeaderProfileID = cmsGetHeaderProfileID +cmsGetHeaderRenderingIntent = cmsGetHeaderRenderingIntent +cmsGetNamedColorList = cmsGetNamedColorList +cmsGetPCS = cmsGetPCS +cmsGetPostScriptColorResource = cmsGetPostScriptColorResource +cmsGetPostScriptCRD = cmsGetPostScriptCRD +cmsGetPostScriptCSA = cmsGetPostScriptCSA +cmsGetProfileInfo = cmsGetProfileInfo +cmsGetProfileInfoASCII = cmsGetProfileInfoASCII +cmsGetProfileContextID = cmsGetProfileContextID +cmsGetProfileVersion = cmsGetProfileVersion +cmsGetSupportedIntents = cmsGetSupportedIntents +cmsGetTagCount = cmsGetTagCount +cmsGetTagSignature = cmsGetTagSignature +cmsGetTransformContextID = cmsGetTransformContextID +_cmsICCcolorSpace = _cmsICCcolorSpace +_cmsIOPrintf = _cmsIOPrintf +cmsIsCLUT = cmsIsCLUT +cmsIsIntentSupported = cmsIsIntentSupported +cmsIsMatrixShaper = cmsIsMatrixShaper +cmsIsTag = cmsIsTag +cmsIsToneCurveDescending = cmsIsToneCurveDescending +cmsIsToneCurveLinear = cmsIsToneCurveLinear +cmsIsToneCurveMonotonic = cmsIsToneCurveMonotonic +cmsIsToneCurveMultisegment = cmsIsToneCurveMultisegment +cmsGetToneCurveParametricType = cmsGetToneCurveParametricType +cmsIT8Alloc = cmsIT8Alloc +cmsIT8DefineDblFormat = cmsIT8DefineDblFormat +cmsIT8EnumDataFormat = cmsIT8EnumDataFormat +cmsIT8EnumProperties = cmsIT8EnumProperties +cmsIT8Free = cmsIT8Free +cmsIT8GetData = cmsIT8GetData +cmsIT8GetDataDbl = cmsIT8GetDataDbl +cmsIT8FindDataFormat = cmsIT8FindDataFormat +cmsIT8GetDataRowCol = cmsIT8GetDataRowCol +cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl +cmsIT8GetPatchName = cmsIT8GetPatchName +cmsIT8GetProperty = cmsIT8GetProperty +cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl +cmsIT8GetSheetType = cmsIT8GetSheetType +cmsIT8LoadFromFile = cmsIT8LoadFromFile +cmsIT8LoadFromMem = cmsIT8LoadFromMem +cmsIT8SaveToFile = cmsIT8SaveToFile +cmsIT8SaveToMem = cmsIT8SaveToMem +cmsIT8SetComment = cmsIT8SetComment +cmsIT8SetData = cmsIT8SetData +cmsIT8SetDataDbl = cmsIT8SetDataDbl +cmsIT8SetDataFormat = cmsIT8SetDataFormat +cmsIT8SetDataRowCol = cmsIT8SetDataRowCol +cmsIT8SetDataRowColDbl = cmsIT8SetDataRowColDbl +cmsIT8SetPropertyDbl = cmsIT8SetPropertyDbl +cmsIT8SetPropertyHex = cmsIT8SetPropertyHex +cmsIT8SetPropertyStr = cmsIT8SetPropertyStr +cmsIT8SetPropertyUncooked = cmsIT8SetPropertyUncooked +cmsIT8SetSheetType = cmsIT8SetSheetType +cmsIT8SetTable = cmsIT8SetTable +cmsIT8SetTableByLabel = cmsIT8SetTableByLabel +cmsIT8TableCount = cmsIT8TableCount +cmsJoinToneCurve = cmsJoinToneCurve +cmsLab2LCh = cmsLab2LCh +cmsLab2XYZ = cmsLab2XYZ +cmsLabEncoded2Float = cmsLabEncoded2Float +cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2 +cmsLCh2Lab = cmsLCh2Lab +_cmsLCMScolorSpace = _cmsLCMScolorSpace +cmsLinkTag = cmsLinkTag +cmsPipelineAlloc = cmsPipelineAlloc +cmsPipelineCat = cmsPipelineCat +cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages +cmsPipelineDup = cmsPipelineDup +cmsPipelineStageCount = cmsPipelineStageCount +cmsPipelineEval16 = cmsPipelineEval16 +cmsPipelineEvalFloat = cmsPipelineEvalFloat +cmsPipelineEvalReverseFloat = cmsPipelineEvalReverseFloat +cmsPipelineFree = cmsPipelineFree +cmsPipelineGetPtrToFirstStage = cmsPipelineGetPtrToFirstStage +cmsPipelineGetPtrToLastStage = cmsPipelineGetPtrToLastStage +cmsPipelineInputChannels = cmsPipelineInputChannels +cmsPipelineInsertStage = cmsPipelineInsertStage +cmsPipelineOutputChannels = cmsPipelineOutputChannels +cmsPipelineSetSaveAs8bitsFlag = cmsPipelineSetSaveAs8bitsFlag +_cmsPipelineSetOptimizationParameters = _cmsPipelineSetOptimizationParameters +cmsPipelineUnlinkStage = cmsPipelineUnlinkStage +_cmsMalloc = _cmsMalloc +_cmsMallocZero = _cmsMallocZero +_cmsMAT3eval = _cmsMAT3eval +_cmsMAT3identity = _cmsMAT3identity +_cmsMAT3inverse = _cmsMAT3inverse +_cmsMAT3isIdentity = _cmsMAT3isIdentity +_cmsMAT3per = _cmsMAT3per +_cmsMAT3solve = _cmsMAT3solve +cmsMD5computeID = cmsMD5computeID +cmsMLUalloc = cmsMLUalloc +cmsMLUdup = cmsMLUdup +cmsMLUfree = cmsMLUfree +cmsMLUgetASCII = cmsMLUgetASCII +cmsMLUgetTranslation = cmsMLUgetTranslation +cmsMLUgetWide = cmsMLUgetWide +cmsMLUsetASCII = cmsMLUsetASCII +cmsMLUsetWide = cmsMLUsetWide +cmsStageAllocCLut16bit = cmsStageAllocCLut16bit +cmsStageAllocCLut16bitGranular = cmsStageAllocCLut16bitGranular +cmsStageAllocCLutFloat = cmsStageAllocCLutFloat +cmsStageAllocCLutFloatGranular = cmsStageAllocCLutFloatGranular +cmsStageAllocToneCurves = cmsStageAllocToneCurves +cmsStageAllocIdentity = cmsStageAllocIdentity +cmsStageAllocMatrix = cmsStageAllocMatrix +_cmsStageAllocPlaceholder = _cmsStageAllocPlaceholder +cmsStageDup = cmsStageDup +cmsStageFree = cmsStageFree +cmsStageNext = cmsStageNext +cmsStageInputChannels = cmsStageInputChannels +cmsStageOutputChannels = cmsStageOutputChannels +cmsStageSampleCLut16bit = cmsStageSampleCLut16bit +cmsStageSampleCLutFloat = cmsStageSampleCLutFloat +cmsStageType = cmsStageType +cmsStageData = cmsStageData +cmsNamedColorCount = cmsNamedColorCount +cmsNamedColorIndex = cmsNamedColorIndex +cmsNamedColorInfo = cmsNamedColorInfo +cmsOpenIOhandlerFromFile = cmsOpenIOhandlerFromFile +cmsOpenIOhandlerFromMem = cmsOpenIOhandlerFromMem +cmsOpenIOhandlerFromNULL = cmsOpenIOhandlerFromNULL +cmsOpenIOhandlerFromStream = cmsOpenIOhandlerFromStream +cmsOpenProfileFromFile = cmsOpenProfileFromFile +cmsOpenProfileFromFileTHR = cmsOpenProfileFromFileTHR +cmsOpenProfileFromIOhandlerTHR = cmsOpenProfileFromIOhandlerTHR +cmsOpenProfileFromMem = cmsOpenProfileFromMem +cmsOpenProfileFromMemTHR = cmsOpenProfileFromMemTHR +cmsOpenProfileFromStream = cmsOpenProfileFromStream +cmsOpenProfileFromStreamTHR = cmsOpenProfileFromStreamTHR +cmsPlugin = cmsPlugin +_cmsRead15Fixed16Number = _cmsRead15Fixed16Number +_cmsReadAlignment = _cmsReadAlignment +_cmsReadFloat32Number = _cmsReadFloat32Number +cmsReadRawTag = cmsReadRawTag +cmsReadTag = cmsReadTag +_cmsReadTypeBase = _cmsReadTypeBase +_cmsReadUInt16Array = _cmsReadUInt16Array +_cmsReadUInt16Number = _cmsReadUInt16Number +_cmsReadUInt32Number = _cmsReadUInt32Number +_cmsReadUInt64Number = _cmsReadUInt64Number +_cmsReadUInt8Number = _cmsReadUInt8Number +_cmsReadXYZNumber = _cmsReadXYZNumber +_cmsRealloc = _cmsRealloc +cmsReverseToneCurve = cmsReverseToneCurve +cmsReverseToneCurveEx = cmsReverseToneCurveEx +cmsSaveProfileToFile = cmsSaveProfileToFile +cmsSaveProfileToIOhandler = cmsSaveProfileToIOhandler +cmsSaveProfileToMem = cmsSaveProfileToMem +cmsSaveProfileToStream = cmsSaveProfileToStream +cmsSetAdaptationState = cmsSetAdaptationState +cmsSetAlarmCodes = cmsSetAlarmCodes +cmsSetColorSpace = cmsSetColorSpace +cmsSetDeviceClass = cmsSetDeviceClass +cmsSetEncodedICCversion = cmsSetEncodedICCversion +cmsSetHeaderAttributes = cmsSetHeaderAttributes +cmsSetHeaderFlags = cmsSetHeaderFlags +cmsSetHeaderManufacturer = cmsSetHeaderManufacturer +cmsSetHeaderModel = cmsSetHeaderModel +cmsSetHeaderProfileID = cmsSetHeaderProfileID +cmsSetHeaderRenderingIntent = cmsSetHeaderRenderingIntent +cmsSetLogErrorHandler = cmsSetLogErrorHandler +cmsSetPCS = cmsSetPCS +cmsSetProfileVersion = cmsSetProfileVersion +cmsSignalError = cmsSignalError +cmsSmoothToneCurve = cmsSmoothToneCurve +cmsstrcasecmp = cmsstrcasecmp +cmsTempFromWhitePoint = cmsTempFromWhitePoint +cmsTransform2DeviceLink = cmsTransform2DeviceLink +cmsUnregisterPlugins = cmsUnregisterPlugins +_cmsVEC3cross = _cmsVEC3cross +_cmsVEC3distance = _cmsVEC3distance +_cmsVEC3dot = _cmsVEC3dot +_cmsVEC3init = _cmsVEC3init +_cmsVEC3length = _cmsVEC3length +_cmsVEC3minus = _cmsVEC3minus +cmsWhitePointFromTemp = cmsWhitePointFromTemp +_cmsWrite15Fixed16Number = _cmsWrite15Fixed16Number +_cmsWriteAlignment = _cmsWriteAlignment +_cmsWriteFloat32Number = _cmsWriteFloat32Number +cmsWriteRawTag = cmsWriteRawTag +cmsWriteTag = cmsWriteTag +_cmsWriteTypeBase = _cmsWriteTypeBase +_cmsWriteUInt16Array = _cmsWriteUInt16Array +_cmsWriteUInt16Number = _cmsWriteUInt16Number +_cmsWriteUInt32Number = _cmsWriteUInt32Number +_cmsWriteUInt64Number = _cmsWriteUInt64Number +_cmsWriteUInt8Number = _cmsWriteUInt8Number +_cmsWriteXYZNumber = _cmsWriteXYZNumber +cmsxyY2XYZ = cmsxyY2XYZ +cmsXYZ2Lab = cmsXYZ2Lab +cmsXYZ2xyY = cmsXYZ2xyY +cmsXYZEncoded2Float = cmsXYZEncoded2Float +cmsSliceSpace16 = cmsSliceSpace16 +cmsSliceSpaceFloat = cmsSliceSpaceFloat +cmsChangeBuffersFormat = cmsChangeBuffersFormat diff --git a/thirdparty/liblcms2/src/lcms2_internal.h b/thirdparty/liblcms2/src/lcms2_internal.h new file mode 100644 index 00000000..84e5a80f --- /dev/null +++ b/thirdparty/liblcms2/src/lcms2_internal.h @@ -0,0 +1,652 @@ + +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#ifndef _lcms_internal_H + +// Include plug-in foundation +#ifndef _lcms_plugin_H +# include "lcms2_plugin.h" +#endif + +// ctype is part of C99 as per 7.1.2 +#include + +// assert macro is part of C99 as per 7.2 +#include + +// Some needed constants +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#ifndef M_LOG10E +# define M_LOG10E 0.434294481903251827651 +#endif + +// BorlandC 5.5 is broken on that +#ifdef __BORLANDC__ +#define sinf(x) (float)sin((float)x) +#define sqrtf(x) (float)sqrt((float)x) +#endif + + +// Alignment of ICC file format uses 4 bytes (cmsUInt32Number) +#define _cmsSIZEOFLONGMINUS1 (sizeof(cmsUInt32Number)-1) +#define _cmsALIGNLONG(x) (((x)+_cmsSIZEOFLONGMINUS1) & ~(_cmsSIZEOFLONGMINUS1)) + +// Maximum encodeable values in floating point +#define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0) +#define MIN_ENCODEABLE_ab2 (-128.0) +#define MAX_ENCODEABLE_ab2 ((65535.0/256.0) - 128.0) +#define MIN_ENCODEABLE_ab4 (-128.0) +#define MAX_ENCODEABLE_ab4 (127.0) + +// Maximum of channels for internal pipeline evaluation +#define MAX_STAGE_CHANNELS 128 + +// Unused parameter warning supression +#define cmsUNUSED_PARAMETER(x) ((void)x) + +// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999). +// unfortunately VisualC++ does not conform that +#if defined(_MSC_VER) || defined(__BORLANDC__) +# define cmsINLINE __inline +#else +# define cmsINLINE static inline +#endif + +// Other replacement functions +#ifdef _MSC_VER +# ifndef snprintf +# define snprintf _snprintf +# endif +# ifndef vsnprintf +# define vsnprintf _vsnprintf +# endif +#endif + +// Pthreads. In windows we use the native WIN32 API instead +#ifdef CMS_DONT_USE_PTHREADS +typedef int LCMS_RWLOCK_T; +# define LCMS_CREATE_LOCK(x) +# define LCMS_FREE_LOCK(x) +# define LCMS_READ_LOCK(x) +# define LCMS_WRITE_LOCK(x) +# define LCMS_UNLOCK(x) +#else +#ifdef CMS_IS_WINDOWS_ +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + typedef CRITICAL_SECTION LCMS_RWLOCK_T; +# define LCMS_CREATE_LOCK(x) InitializeCriticalSection((x)) +# define LCMS_FREE_LOCK(x) DeleteCriticalSection((x)) +# define LCMS_READ_LOCK(x) EnterCriticalSection((x)) +# define LCMS_WRITE_LOCK(x) EnterCriticalSection((x)) +# define LCMS_UNLOCK(x) LeaveCriticalSection((x)) +#else +# include + typedef pthread_rwlock_t LCMS_RWLOCK_T; +# define LCMS_CREATE_LOCK(x) pthread_rwlock_init((x), NULL) +# define LCMS_FREE_LOCK(x) pthread_rwlock_destroy((x)) +# define LCMS_READ_LOCK(x) pthread_rwlock_rdlock((x)) +# define LCMS_WRITE_LOCK(x) pthread_rwlock_wrlock((x)) +# define LCMS_UNLOCK(x) pthread_rwlock_unlock((x)) +#endif +#endif + +// A fast way to convert from/to 16 <-> 8 bits +#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) +#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF) + +// Code analysis is broken on asserts +#ifdef _MSC_VER +# if (_MSC_VER >= 1500) +# define _cmsAssert(a) { assert((a)); __analysis_assume((a)); } +# else +# define _cmsAssert(a) assert((a)) +# endif +#else +# define _cmsAssert(a) assert((a)) +#endif + +//--------------------------------------------------------------------------------- + +// Determinant lower than that are assumed zero (used on matrix invert) +#define MATRIX_DET_TOLERANCE 0.0001 + +//--------------------------------------------------------------------------------- + +// Fixed point +#define FIXED_TO_INT(x) ((x)>>16) +#define FIXED_REST_TO_INT(x) ((x)&0xFFFFU) +#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16) + +cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); } +cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); } + +// ----------------------------------------------------------------------------------------------------------- + +// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon +// note than this only works in the range ..-32767...+32767 because +// mantissa is interpreted as 15.16 fixed point. +// The union is to avoid pointer aliasing overoptimization. +cmsINLINE int _cmsQuickFloor(cmsFloat64Number val) +{ +#ifdef CMS_DONT_USE_FAST_FLOOR + return (int) floor(val); +#else + const cmsFloat64Number _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor + union { + cmsFloat64Number val; + int halves[2]; + } temp; + + temp.val = val + _lcms_double2fixmagic; + +#ifdef CMS_USE_BIG_ENDIAN + return temp.halves[1] >> 16; +#else + return temp.halves[0] >> 16; +#endif +#endif +} + +// Fast floor restricted to 0..65535.0 +cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d) +{ + return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U; +} + +// Floor to word, taking care of saturation +cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) +{ + d += 0.5; + if (d <= 0) return 0; + if (d >= 65535.0) return 0xffff; + + return _cmsQuickFloorWord(d); +} + +// Plug-In registering --------------------------------------------------------------- + +// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. +void* _cmsPluginMalloc(cmsUInt32Number size); + +// Memory management +cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); + +// Interpolation +cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); + +// Parametric curves +cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Plugin); + +// Formatters management +cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Plugin); + +// Tag type management +cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Plugin); + +// Tag management +cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Plugin); + +// Intent management +cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Plugin); + +// Multi Process elements +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin); + +// Optimization +cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin); + + +// --------------------------------------------------------------------------------------------------------- + +// Suballocators. Those are blocks of memory that is freed at the end on whole block. +typedef struct _cmsSubAllocator_chunk_st { + + cmsUInt8Number* Block; + cmsUInt32Number BlockSize; + cmsUInt32Number Used; + + struct _cmsSubAllocator_chunk_st* next; + +} _cmsSubAllocator_chunk; + + +typedef struct { + + cmsContext ContextID; + _cmsSubAllocator_chunk* h; + +} _cmsSubAllocator; + + +_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); +void _cmsSubAllocDestroy(_cmsSubAllocator* s); +void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); + +// ---------------------------------------------------------------------------------- + +// MLU internal representation +typedef struct { + + cmsUInt16Number Language; + cmsUInt16Number Country; + + cmsUInt32Number StrW; // Offset to current unicode string + cmsUInt32Number Len; // Lenght in bytes + +} _cmsMLUentry; + +struct _cms_MLU_struct { + + cmsContext ContextID; + + // The directory + int AllocatedEntries; + int UsedEntries; + _cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool + + // The Pool + cmsUInt32Number PoolSize; // The maximum allocated size + cmsUInt32Number PoolUsed; // The used size + void* MemPool; // Pointer to begin of memory pool +}; + +// Named color list internal representation +typedef struct { + + char Name[cmsMAX_PATH]; + cmsUInt16Number PCS[3]; + cmsUInt16Number DeviceColorant[cmsMAXCHANNELS]; + +} _cmsNAMEDCOLOR; + +struct _cms_NAMEDCOLORLIST_struct { + + cmsUInt32Number nColors; + cmsUInt32Number Allocated; + cmsUInt32Number ColorantCount; + + char Prefix[33]; // Prefix and suffix are defined to be 32 characters at most + char Suffix[33]; + + _cmsNAMEDCOLOR* List; + + cmsContext ContextID; +}; + + +// ---------------------------------------------------------------------------------- + +// This is the internal struct holding profile details. + +// Maximum supported tags in a profile +#define MAX_TABLE_TAG 100 + +typedef struct _cms_iccprofile_struct { + + // I/O handler + cmsIOHANDLER* IOhandler; + + // The thread ID + cmsContext ContextID; + + // Creation time + struct tm Created; + + // Only most important items found in ICC profiles + cmsUInt32Number Version; + cmsProfileClassSignature DeviceClass; + cmsColorSpaceSignature ColorSpace; + cmsColorSpaceSignature PCS; + cmsUInt32Number RenderingIntent; + cmsUInt32Number flags; + cmsUInt32Number manufacturer, model; + cmsUInt64Number attributes; + + cmsProfileID ProfileID; + + // Dictionary + cmsUInt32Number TagCount; + cmsTagSignature TagNames[MAX_TABLE_TAG]; + cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to wich is linked (0=none) + cmsUInt32Number TagSizes[MAX_TABLE_TAG]; // Size on disk + cmsUInt32Number TagOffsets[MAX_TABLE_TAG]; + cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked + void * TagPtrs[MAX_TABLE_TAG]; + cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types + // depending on profile version, so we keep track of the // type handler for each tag in the list. + // Special + cmsBool IsWrite; + +} _cmsICCPROFILE; + +// IO helpers for profiles +cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc); +cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace); +int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); + +// Tag types +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig); +cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); +cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig); + +// Error logging --------------------------------------------------------------------------------------------------------- + +void _cmsTagSignature2String(char String[5], cmsTagSignature sig); + +// Interpolation --------------------------------------------------------------------------------------------------------- + +cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); +cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); +void _cmsFreeInterpParams(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p); + +// Curves ---------------------------------------------------------------------------------------------------------------- + +// This struct holds information about a segment, plus a pointer to the function that implements the evaluation. +// In the case of table-based, Eval pointer is set to NULL + +// The gamma function main structure +struct _cms_curve_struct { + + cmsInterpParams* InterpParams; // Private optimizations for interpolation + + cmsUInt32Number nSegments; // Number of segments in the curve. Zero for a 16-bit based tables + cmsCurveSegment* Segments; // The segments + cmsInterpParams** SegInterp; // Array of private optimizations for interpolation in table-based segments + + cmsParametricCurveEvaluator* Evals; // Evaluators (one per segment) + + // 16 bit Table-based representation follows + cmsUInt32Number nEntries; // Number of table elements + cmsUInt16Number* Table16; // The table itself. +}; + + +// Pipelines & Stages --------------------------------------------------------------------------------------------- + +// A single stage +struct _cmsStage_struct { + + cmsContext ContextID; + + cmsStageSignature Type; // Identifies the stage + cmsStageSignature Implements; // Identifies the *function* of the stage (for optimizations) + + cmsUInt32Number InputChannels; // Input channels -- for optimization purposes + cmsUInt32Number OutputChannels; // Output channels -- for optimization purposes + + _cmsStageEvalFn EvalPtr; // Points to fn that evaluates the stage (always in floating point) + _cmsStageDupElemFn DupElemPtr; // Points to a fn that duplicates the *data* of the stage + _cmsStageFreeElemFn FreePtr; // Points to a fn that sets the *data* of the stage free + + // A generic pointer to whatever memory needed by the stage + void* Data; + + // Maintains linked list (used internally) + struct _cmsStage_struct* Next; +}; + +// Data kept in "Element" member of cmsStage + +// Curves +typedef struct { + cmsUInt32Number nCurves; + cmsToneCurve** TheCurves; + +} _cmsStageToneCurvesData; + +// Matrix +typedef struct { + cmsFloat64Number* Double; // floating point for the matrix + cmsFloat64Number* Offset; // The offset + +} _cmsStageMatrixData; + +// CLUT +typedef struct { + + union { // Can have only one of both representations at same time + cmsUInt16Number* T; // Points to the table 16 bits table + cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table + + } Tab; + + cmsInterpParams* Params; + cmsUInt32Number nEntries; + cmsBool HasFloatValues; + +} _cmsStageCLutData; + + +// Special Stages (cannot be saved) +cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID); +cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID); +cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID); +cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID); +cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID); +cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID); +cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList); +cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels); +cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan); + +// For curve set only +cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe); + + +// Pipeline Evaluator (in floating point) +typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const void* Data); + +struct _cmsPipeline_struct { + + cmsStage* Elements; // Points to elements chain + cmsUInt32Number InputChannels, OutputChannels; + + // Data & evaluators + void *Data; + + _cmsOPTeval16Fn Eval16Fn; + _cmsPipelineEvalFloatFn EvalFloatFn; + _cmsOPTfreeDataFn FreeDataFn; + _cmsOPTdupDataFn DupDataFn; + + cmsContext ContextID; // Environment + + cmsBool SaveAs8Bits; // Implemntation-specific: save as 8 bits if possible +}; + +// LUT reading & creation ------------------------------------------------------------------------------------------- + +// Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy +// of the LUTS, since ownership of original is up to the profile. The user should free allocated resources. + +cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent); +cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent); +cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent); + +// Special values +cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile); +cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile); + +// Profile linker -------------------------------------------------------------------------------------------------- + +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +// Sequence -------------------------------------------------------------------------------------------------------- + +cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile); +cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq); +cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]); + + +// LUT optimization ------------------------------------------------------------------------------------------------ + +cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples); +int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags); + +cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, + cmsUInt16Number **White, + cmsUInt16Number **Black, + cmsUInt32Number *nOutputs); + +cmsBool _cmsOptimizePipeline(cmsPipeline** Lut, + int Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags ); + + +// Hi level LUT building ---------------------------------------------------------------------------------------------- + +cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number nGamutPCSposition, + cmsHPROFILE hGamut); + + +// Formatters ------------------------------------------------------------------------------------------------------------ + +#define cmsFLAGS_CAN_CHANGE_FORMATTER 0x02000000 // Allow change buffer format + +cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); +cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); + +cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags); + + +// Transform logic ------------------------------------------------------------------------------------------------------ + +struct _cmstransform_struct; + +// Full xform +typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform, + const void* InputBuffer, + void* OutputBuffer, cmsUInt32Number Size); + +typedef struct { + + cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference + cmsUInt32Number StrideIn, StrideOut; // Planar support + +} cmsFormatterInfo; + +// Transformation +typedef struct _cmstransform_struct { + + cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference + + // Points to transform code + _cmsTransformFn xform; + + // Formatters, cannot be embedded into LUT because cache + cmsFormatter16 FromInput; + cmsFormatter16 ToOutput; + + cmsFormatterFloat FromInputFloat; + cmsFormatterFloat ToOutputFloat; + + // 1-pixel cache (16 bits only) + cmsUInt16Number CacheIn[cmsMAXCHANNELS]; + cmsUInt16Number CacheOut[cmsMAXCHANNELS]; + + // Semaphor for cache + LCMS_RWLOCK_T rwlock; + + // A MPE LUT holding the full (optimized) transform + cmsPipeline* Lut; + + // A MPE LUT holding the gamut check. It goes from the input space to bilevel + cmsPipeline* GamutCheck; + + // Colorant tables + cmsNAMEDCOLORLIST* InputColorant; // Input Colorant table + cmsNAMEDCOLORLIST* OutputColorant; // Colorant table (for n chans > CMYK) + + // Informational only + cmsColorSpaceSignature EntryColorSpace; + cmsColorSpaceSignature ExitColorSpace; + + // Profiles used to create the transform + cmsSEQ* Sequence; + + cmsUInt32Number dwOriginalFlags; + cmsFloat64Number AdaptationState; + + // The intent of this transform. That is usually the last intent in the profilechain, but may differ + cmsUInt32Number RenderingIntent; + + // An id that uniquely identifies the running context. May be null. + cmsContext ContextID; + +} _cmsTRANSFORM; + +// -------------------------------------------------------------------------------------------------- + +cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + + +cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll); + +cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries); + + +#define _lcms_internal_H +#endif diff --git a/thirdparty/libpng/CMakeLists.txt b/thirdparty/libpng/CMakeLists.txt new file mode 100644 index 00000000..7f6456fb --- /dev/null +++ b/thirdparty/libpng/CMakeLists.txt @@ -0,0 +1,29 @@ +PROJECT(libpng C) + +INCLUDE_DIRECTORIES( + "${CMAKE_CURRENT_SOURCE_DIR}" + ${OPENJPEG_SOURCE_DIR}/thirdparty/include +) + +FILE(GLOB SRCS *.c) +FILE(GLOB HDRS *.h) +SET(EXT_HDRS + ${OPENJPEG_SOURCE_DIR}/thirdparty/include/zlib.h + ${OPENJPEG_SOURCE_DIR}/thirdparty/include/zconf.h +) +# +SET(LIBTARGET "png") +# +ADD_LIBRARY(${LIBTARGET} STATIC ${SRCS} ${HDRS} ${EXT_HDRS}) +# +IF(MSVC) + SET_TARGET_PROPERTIES(${LIBTARGET} PROPERTIES PREFIX "lib") +ENDIF(MSVC) +# +TARGET_LINK_LIBRARIES(${LIBTARGET} ${Z_LIBNAME} ${M_LIBRARY}) +# +SET_TARGET_PROPERTIES(${LIBTARGET} + PROPERTIES + OUTPUT_NAME "${LIBTARGET}" + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/thirdparty/lib) +# diff --git a/thirdparty/libpng/LICENSE b/thirdparty/libpng/LICENSE new file mode 100644 index 00000000..756ebd04 --- /dev/null +++ b/thirdparty/libpng/LICENSE @@ -0,0 +1,111 @@ + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.2.6, August 15, 2004, through 1.4.4, September 23, 2010, are +Copyright (c) 2004, 2006-2010 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +September 23, 2010 diff --git a/thirdparty/libpng/example.c b/thirdparty/libpng/example.c new file mode 100644 index 00000000..d7391734 --- /dev/null +++ b/thirdparty/libpng/example.c @@ -0,0 +1,838 @@ + +#if 0 /* in case someone actually tries to compile this */ + +/* example.c - an example of using libpng + * Last changed in libpng 1.4.2 [May 6, 2010] + * This file has been placed in the public domain by the authors. + * Maintained 1998-2010 Glenn Randers-Pehrson + * Maintained 1996, 1997 Andreas Dilger) + * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* This is an example of how to use libpng to read and write PNG files. + * The file libpng.txt is much more verbose then this. If you have not + * read it, do so first. This was designed to be a starting point of an + * implementation. This is not officially part of libpng, is hereby placed + * in the public domain, and therefore does not require a copyright notice. + * + * This file does not currently compile, because it is missing certain + * parts, like allocating memory to hold an image. You will have to + * supply these parts to get it to compile. For an example of a minimal + * working PNG reader/writer, see pngtest.c, included in this distribution; + * see also the programs in the contrib directory. + */ + +#include "png.h" + + /* The png_jmpbuf() macro, used in error handling, became available in + * libpng version 1.0.6. If you want to be able to run your code with older + * versions of libpng, you must define the macro yourself (but only if it + * is not already defined by libpng!). + */ + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +#define PNG_BYTES_TO_CHECK 4 +int check_if_png(char *file_name, FILE **fp) +{ + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if ((*fp = fopen(file_name, "rb")) == NULL) + return 0; + + /* Read in some of the signature bytes */ + if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) + return 0; + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + + return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +/* Read a PNG file. You may want to return an error code if the read + * fails (depending upon the failure). There are two "prototypes" given + * here - one where we are given the filename, and we need to open the + * file, and the other where we are given an open file (possibly with + * some or all of the magic bytes read - see comments above). + */ +#ifdef open_file /* prototype 1 */ +void read_png(char *file_name) /* We need to open the file */ +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned int sig_read = 0; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + FILE *fp; + + if ((fp = fopen(file_name, "rb")) == NULL) + return (ERROR); + +#else no_open_file /* prototype 2 */ +void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; +#endif no_open_file /* Only use one prototype! */ + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also supply the + * the compiler header file version, so that we know if the application + * was compiled with a compatible version of the library. REQUIRED + */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the memory for image information. REQUIRED. */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return (ERROR); + } + + /* Set error handling if you are using the setjmp/longjmp method (this is + * the normal method of doing things with libpng). REQUIRED unless you + * set up your own error handlers in the png_create_read_struct() earlier. + */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + /* Free all of the memory associated with the png_ptr and info_ptr */ + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(fp); + /* If we get here, we had a problem reading the file */ + return (ERROR); + } + + /* One of the following I/O initialization methods is REQUIRED */ +#ifdef streams /* PNG file I/O method 1 */ + /* Set up the input control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* PNG file I/O method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call: + */ + png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Use only one I/O method! */ + + /* If we have already read some of the signature */ + png_set_sig_bytes(png_ptr, sig_read); + +#ifdef hilevel + /* + * If you have enough memory to read in the entire image at once, + * and you need to specify only transforms that can be controlled + * with one of the PNG_TRANSFORM_* bits (this presently excludes + * quantizing, filling, setting background, and doing gamma + * adjustment), then you can read the entire image (including + * pixels) into the info structure with this call: + */ + png_read_png(png_ptr, info_ptr, png_transforms, NULL); + +#else + /* OK, you're doing it the hard way, with the lower-level functions */ + + /* The call to png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). REQUIRED + */ + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + + /* Set up the data transformations you want. Note that these are all + * optional. Only call them if you want/need them. Many of the + * transformations only work on specific types of images, and many + * are mutually exclusive. + */ + + /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ + png_set_strip_16(png_ptr); + + /* Strip alpha bytes from the input data without combining with the + * background (not recommended). + */ + png_set_strip_alpha(png_ptr); + + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + png_set_packing(png_ptr); + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). */ + png_set_packswap(png_ptr); + + /* Expand paletted colors into true RGB triplets */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + + /* Expand paletted or RGB images with transparency to full alpha channels + * so the data will be available as RGBA quartets. + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + + /* Set the background color to draw transparent and alpha images over. + * It is possible to set the red, green, and blue components directly + * for paletted images instead of supplying a palette index. Note that + * even if the PNG file supplies a background, you are not required to + * use it - you should use the (solid) application background if it has one. + */ + + png_color_16 my_background, *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + /* Some suggestions as to how to get a screen gamma value + * + * Note that screen gamma is the display_exponent, which includes + * the CRT_exponent and any correction for viewing conditions + */ + if (/* We have a user-defined screen gamma value */) + { + screen_gamma = user-defined screen_gamma; + } + /* This is one way that applications share the same screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) + { + screen_gamma = atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a PC monitor in a dimly + lit room */ + screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ + } + + /* Tell libpng to handle the gamma conversion for you. The final call + * is a good guess for PC generated images, but it should be configurable + * by the user at run time by the user. It is strongly suggested that + * your application support gamma correction. + */ + + int intent; + + if (png_get_sRGB(png_ptr, info_ptr, &intent)) + png_set_gamma(png_ptr, screen_gamma, 0.45455); + else + { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) + png_set_gamma(png_ptr, screen_gamma, image_gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + /* Quantize RGB files down to 8 bit palette or reduce palettes + * to the number of colors available on your screen. + */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + int num_palette; + png_colorp palette; + + /* This reduces the image to the application supplied palette */ + if (/* We have our own palette */) + { + /* An array of colors to which the image should be quantized */ + png_color std_color_cube[MAX_SCREEN_COLORS]; + + /* Prior to libpng-1.4.2, this was png_set_dither(). */ + png_set_quantize(png_ptr, std_color_cube, MAX_SCREEN_COLORS, + MAX_SCREEN_COLORS, NULL, 0); + } + /* This reduces the image to the palette supplied in the file */ + else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, &histogram); + + png_set_quantize(png_ptr, palette, num_palette, + max_screen_colors, histogram, 0); + } + } +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ + + /* Invert monochrome files to have 0 as white and 1 as black */ + png_set_invert_mono(png_ptr); + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit_p; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); + png_set_shift(png_ptr, sig_bit_p); + } + + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (color_type & PNG_COLOR_MASK_COLOR) + png_set_bgr(png_ptr); + + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + png_set_swap_alpha(png_ptr); + + /* Swap bytes of 16 bit files to least significant byte first */ + png_set_swap(png_ptr); + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + + /* Turn on interlace handling. REQUIRED if you are not using + * png_read_image(). To see how to handle interlacing passes, + * see the png_read_row() method below: + */ + number_passes = png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (ie you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* Allocate the memory to hold the image using the fields of info_ptr. */ + + /* The easiest way to read the image: */ + png_bytep row_pointers[height]; + + /* Clear the pointer array */ + for (row = 0; row < height; row++) + row_pointers[row] = NULL; + + for (row = 0; row < height; row++) + row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + + /* Now it's time to read the image. One of these methods is REQUIRED */ +#ifdef entire /* Read the entire image in one go */ + png_read_image(png_ptr, row_pointers); + +#else no_entire /* Read the image one or more scanlines at a time */ + /* The other way to read images - deal with interlacing: */ + + for (pass = 0; pass < number_passes; pass++) + { +#ifdef single /* Read the image a single row at a time */ + for (y = 0; y < height; y++) + { + png_read_rows(png_ptr, &row_pointers[y], NULL, 1); + } + +#else no_single /* Read the image several rows at a time */ + for (y = 0; y < height; y += number_of_rows) + { +#ifdef sparkle /* Read the image using the "sparkle" effect. */ + png_read_rows(png_ptr, &row_pointers[y], NULL, + number_of_rows); +#else no_sparkle /* Read the image using the "rectangle" effect */ + png_read_rows(png_ptr, NULL, &row_pointers[y], + number_of_rows); +#endif no_sparkle /* Use only one of these two methods */ + } + + /* If you want to display the image after every pass, do so here */ +#endif no_single /* Use only one of these two methods */ + } +#endif no_entire /* Use only one of these two methods */ + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); +#endif hilevel + + /* At this point you have read the entire image */ + + /* Clean up after the read, and free any memory allocated - REQUIRED */ + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return (OK); +} + +/* Progressively read a file */ + +int +initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) +{ + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible in case we are using dynamically + * linked libraries. + */ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (*png_ptr == NULL) + { + *info_ptr = NULL; + return (ERROR); + } + + *info_ptr = png_create_info_struct(png_ptr); + + if (*info_ptr == NULL) + { + png_destroy_read_struct(png_ptr, info_ptr, NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf((*png_ptr)))) + { + png_destroy_read_struct(png_ptr, info_ptr, NULL); + return (ERROR); + } + + /* This one's new. You will need to provide all three + * function callbacks, even if you aren't using them all. + * If you aren't using all functions, you can specify NULL + * parameters. Even when all three functions are NULL, + * you need to call png_set_progressive_read_fn(). + * These functions shouldn't be dependent on global or + * static variables if you are decoding several images + * simultaneously. You should store stream specific data + * in a separate struct, given as the second parameter, + * and retrieve the pointer from inside the callbacks using + * the function png_get_progressive_ptr(png_ptr). + */ + png_set_progressive_read_fn(*png_ptr, (void *)stream_data, + info_callback, row_callback, end_callback); + + return (OK); +} + +int +process_data(png_structp *png_ptr, png_infop *info_ptr, + png_bytep buffer, png_uint_32 length) +{ + if (setjmp(png_jmpbuf((*png_ptr)))) + { + /* Free the png_ptr and info_ptr memory on error */ + png_destroy_read_struct(png_ptr, info_ptr, NULL); + return (ERROR); + } + + /* This one's new also. Simply give it chunks of data as + * they arrive from the data stream (in order, of course). + * On segmented machines, don't give it any more than 64K. + * The library seems to run fine with sizes of 4K, although + * you can give it much less if necessary (I assume you can + * give it chunks of 1 byte, but I haven't tried with less + * than 256 bytes yet). When this function returns, you may + * want to display any rows that were generated in the row + * callback, if you aren't already displaying them there. + */ + png_process_data(*png_ptr, *info_ptr, buffer, length); + return (OK); +} + +info_callback(png_structp png_ptr, png_infop info) +{ + /* Do any setup here, including setting any of the transformations + * mentioned in the Reading PNG files section. For now, you _must_ + * call either png_start_read_image() or png_read_update_info() + * after all the transformations are set (even if you don't set + * any). You may start getting rows before png_process_data() + * returns, so this is your last chance to prepare for that. + */ +} + +row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ + /* + * This function is called for every row in the image. If the + * image is interlaced, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * + * In this function you will receive a pointer to new row data from + * libpng called new_row that is to replace a corresponding row (of + * the same data format) in a buffer allocated by your application. + * + * The new row data pointer "new_row" may be NULL, indicating there is + * no new data to be replaced (in cases of interlace loading). + * + * If new_row is not NULL then you need to call + * png_progressive_combine_row() to replace the corresponding row as + * shown below: + */ + + /* Get pointer to corresponding row in our + * PNG read buffer. + */ + png_bytep old_row = ((png_bytep *)our_data)[row_num]; + + /* If both rows are allocated then copy the new row + * data to the corresponding row data. + */ + if ((old_row != NULL) && (new_row != NULL)) + png_progressive_combine_row(png_ptr, old_row, new_row); + + /* + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the new row and the + * old row, as demonstrated above. You can call this function for + * NULL rows (it will just return) and for non-interlaced images + * (it just does the png_memcpy for you) if it will make the code + * easier. Thus, you can just do this for all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, new_row); + + /* where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * to pass the current row as new_row, and the function will combine + * the old row and the new row. + */ +} + +end_callback(png_structp png_ptr, png_infop info) +{ + /* This function is called when the whole image has been read, + * including any chunks after the image (up to and including + * the IEND). You will usually have the same info chunk as you + * had in the header, although some data may have been added + * to the comments and time fields. + * + * Most people won't do much here, perhaps setting a flag that + * marks the image as finished. + */ +} + +/* Write a png file */ +void write_png(char *file_name /* , ... other image information ... */) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette; + + /* Open the file */ + fp = fopen(file_name, "wb"); + if (fp == NULL) + return (ERROR); + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the image information data. REQUIRED */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_write_struct(&png_ptr, NULL); + return (ERROR); + } + + /* Set error handling. REQUIRED if you aren't supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png_ptr))) + { + /* If we get here, we had a problem writing the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, &info_ptr); + return (ERROR); + } + + /* One of the following I/O initialization functions is REQUIRED */ + +#ifdef streams /* I/O initialization method 1 */ + /* Set up the output control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* I/O initialization method 2 */ + /* If you are using replacement write functions, instead of calling + * png_init_io() here you would call + */ + png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, + user_IO_flush_function); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Only use one initialization method */ + +#ifdef hilevel + /* This is the easy way. Use it if you already have all the + * image info living in the structure. You could "|" many + * PNG_TRANSFORM flags into the png_transforms integer here. + */ + png_write_png(png_ptr, info_ptr, png_transforms, NULL); + +#else + /* This is the hard way */ + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + */ + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, + PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Set the palette if there is one. REQUIRED for indexed-color images */ + palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH + * png_sizeof(png_color)); + /* ... Set palette colors ... */ + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + /* You must not free palette here, because png_set_PLTE only makes a link to + * the palette that you malloced. Wait until you are about to destroy + * the png structure. + */ + + /* Optional significant bit (sBIT) chunk */ + png_color_8 sig_bit; + /* If we are dealing with a grayscale image then */ + sig_bit.gray = true_bit_depth; + /* Otherwise, if we are dealing with a color image then */ + sig_bit.red = true_red_bit_depth; + sig_bit.green = true_green_bit_depth; + sig_bit.blue = true_blue_bit_depth; + /* If the image has an alpha channel then */ + sig_bit.alpha = true_alpha_bit_depth; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + + /* Optional gamma chunk is strongly suggested if you have any guess + * as to the correct gamma of the image. + */ + png_set_gAMA(png_ptr, info_ptr, gamma); + + /* Optionally write comments into the image */ + text_ptr[0].key = "Title"; + text_ptr[0].text = "Mona Lisa"; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[1].key = "Author"; + text_ptr[1].text = "Leonardo DaVinci"; + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[2].key = "Description"; + text_ptr[2].text = ""; + text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; +#ifdef PNG_iTXt_SUPPORTED + text_ptr[0].lang = NULL; + text_ptr[0].lang_key = NULL; + text_ptr[1].lang = NULL; + text_ptr[1].lang_key = NULL; + text_ptr[2].lang = NULL; + text_ptr[2].lang_key = NULL; +#endif + png_set_text(png_ptr, info_ptr, text_ptr, 3); + + /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ + + /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored + * on read and, if your application chooses to write them, they must + * be written in accordance with the sRGB profile + */ + + /* Write the file header information. REQUIRED */ + png_write_info(png_ptr, info_ptr); + + /* If you want, you can write the info in two steps, in case you need to + * write your private chunk ahead of PLTE: + * + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + * write_my_chunk(); + * png_write_info(png_ptr, info_ptr); + * + * However, given the level of known- and unknown-chunk support in 1.2.0 + * and up, this should no longer be necessary. + */ + + /* Once we write out the header, the compression type on the text + * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or + * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again + * at the end. + */ + + /* Set up the transformations you want. Note that these are + * all optional. Only call them if you want them. + */ + + /* Invert monochrome pixels */ + png_set_invert_mono(png_ptr); + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + png_set_shift(png_ptr, &sig_bit); + + /* Pack pixels into bytes */ + png_set_packing(png_ptr); + + /* Swap location of alpha bytes from ARGB to RGBA */ + png_set_swap_alpha(png_ptr); + + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + + /* Flip BGR pixels to RGB */ + png_set_bgr(png_ptr); + + /* Swap bytes of 16-bit files to most significant byte first */ + png_set_swap(png_ptr); + + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + png_set_packswap(png_ptr); + + /* Turn on interlace handling if you are not using png_write_image() */ + if (interlacing) + number_passes = png_set_interlace_handling(png_ptr); + else + number_passes = 1; + + /* The easiest way to write the image (you may have a different memory + * layout, however, so choose what fits your needs best). You need to + * use the first method if you aren't handling interlacing yourself. + */ + png_uint_32 k, height, width; + png_byte image[height][width*bytes_per_pixel]; + png_bytep row_pointers[height]; + + if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error (png_ptr, "Image is too tall to process in memory"); + + for (k = 0; k < height; k++) + row_pointers[k] = image + k*width*bytes_per_pixel; + + /* One of the following output methods is REQUIRED */ + +#ifdef entire /* Write out the entire image data in one call */ + png_write_image(png_ptr, row_pointers); + + /* The other way to write the image - deal with interlacing */ + +#else no_entire /* Write out the image data by one or more scanlines */ + + /* The number of passes is either 1 for non-interlaced images, + * or 7 for interlaced images. + */ + for (pass = 0; pass < number_passes; pass++) + { + /* Write a few rows at a time. */ + png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); + + /* If you are only writing one row at a time, this works */ + for (y = 0; y < height; y++) + png_write_rows(png_ptr, &row_pointers[y], 1); + } +#endif no_entire /* Use only one output method */ + + /* You can write optional chunks like tEXt, zTXt, and tIME at the end + * as well. Shouldn't be necessary in 1.2.0 and up as all the public + * chunks are supported and you can use png_set_unknown_chunks() to + * register unknown chunks into the info structure to be written out. + */ + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); +#endif hilevel + + /* If you png_malloced a palette, free it here (don't free info_ptr->palette, + * as recommended in versions 1.0.5m and earlier of this example; if + * libpng mallocs info_ptr->palette, libpng will free it). If you + * allocated it with malloc() instead of png_malloc(), use free() instead + * of png_free(). + */ + png_free(png_ptr, palette); + palette = NULL; + + /* Similarly, if you png_malloced any data that you passed in with + * png_set_something(), such as a hist or trans array, free it here, + * when you can be sure that libpng is through with it. + */ + png_free(png_ptr, trans); + trans = NULL; + /* Whenever you use png_free() it is a good idea to set the pointer to + * NULL in case your application inadvertently tries to png_free() it + * again. When png_free() sees a NULL it returns without action, thus + * avoiding the double-free security problem. + */ + + /* Clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return (OK); +} + +#endif /* if 0 */ diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c new file mode 100644 index 00000000..f2e5888f --- /dev/null +++ b/thirdparty/libpng/png.c @@ -0,0 +1,918 @@ + +/* png.c - location for general purpose libpng functions + * + * Last changed in libpng 1.4.2 [May 6, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_NO_EXTERN +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#include "pngpriv.h" + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_4_4 Your_png_h_is_not_version_1_4_4; + +/* Version information for C files. This had better match the version + * string defined in png.h. + */ + +/* Tells libpng that we have already handled the first "num_bytes" bytes + * of the PNG file signature. If the PNG data is embedded into another + * stream we can set num_bytes = 8 so that libpng will not attempt to read + * or write any of the magic bytes before it starts on the IHDR. + */ + +#ifdef PNG_READ_SUPPORTED +void PNGAPI +png_set_sig_bytes(png_structp png_ptr, int num_bytes) +{ + png_debug(1, "in png_set_sig_bytes"); + + if (png_ptr == NULL) + return; + + if (num_bytes > 8) + png_error(png_ptr, "Too many bytes for PNG signature"); + + png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behaviour as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + if (num_to_check > 8) + num_to_check = 8; + else if (num_to_check < 1) + return (-1); + + if (start > 7) + return (-1); + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); +} + +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Function to allocate memory for zlib and clear it to 0. */ +voidpf /* PRIVATE */ +png_zalloc(voidpf png_ptr, uInt items, uInt size) +{ + png_voidp ptr; + png_structp p=(png_structp)png_ptr; + png_uint_32 save_flags=p->flags; + png_alloc_size_t num_bytes; + + if (png_ptr == NULL) + return (NULL); + if (items > PNG_UINT_32_MAX/size) + { + png_warning (p, "Potential overflow in png_zalloc()"); + return (NULL); + } + num_bytes = (png_alloc_size_t)items * size; + + p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; + ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); + p->flags=save_flags; + + return ((voidpf)ptr); +} + +/* Function to free memory for zlib */ +void /* PRIVATE */ +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free((png_structp)png_ptr, (png_voidp)ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structp png_ptr) +{ + png_ptr->crc = crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + if (need_crc) + png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); +} + +/* Allocate the memory for an info_struct for the application. We don't + * really need the png_ptr, but it could potentially be useful in the + * future. This should be used in favour of malloc(png_sizeof(png_info)) + * and png_info_init() so that applications that want to use a shared + * libpng don't have to be recompiled if png_info changes size. + */ +png_infop PNGAPI +png_create_info_struct(png_structp png_ptr) +{ + png_infop info_ptr; + + png_debug(1, "in png_create_info_struct"); + + if (png_ptr == NULL) + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, + png_ptr->malloc_fn, png_ptr->mem_ptr); +#else + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); +#endif + if (info_ptr != NULL) + png_info_init_3(&info_ptr, png_sizeof(png_info)); + + return (info_ptr); +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. + */ +void PNGAPI +png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) +{ + png_infop info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct"); + + if (png_ptr == NULL) + return; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + png_info_destroy(png_ptr, info_ptr); + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, + png_ptr->mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. + */ + +void PNGAPI +png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) +{ + png_infop info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3"); + + if (info_ptr == NULL) + return; + + if (png_sizeof(png_info) > png_info_struct_size) + { + png_destroy_struct(info_ptr); + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); + *ptr_ptr = info_ptr; + } + + /* Set everything to 0 */ + png_memset(info_ptr, 0, png_sizeof(png_info)); +} + +void PNGAPI +png_data_freer(png_structp png_ptr, png_infop info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + else if (freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + else + png_warning(png_ptr, + "Unknown freer parameter in png_data_freer"); +} + +void PNGAPI +png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_TEXT_SUPPORTED + /* Free text item num or (if num == -1) all text items */ + if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) + { + if (num != -1) + { + if (info_ptr->text && info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + } + else + { + int i; + for (i = 0; i < info_ptr->num_text; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text=0; + } + } +#endif + +#ifdef PNG_tRNS_SUPPORTED + /* Free any tRNS entry */ + if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->trans_alpha); + info_ptr->trans_alpha = NULL; + info_ptr->valid &= ~PNG_INFO_tRNS; + } +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* Free any sCAL entry */ + if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) + { +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; +#endif + info_ptr->valid &= ~PNG_INFO_sCAL; + } +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* Free any pCAL entry */ + if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + if (info_ptr->pcal_params != NULL) + { + int i; + for (i = 0; i < (int)info_ptr->pcal_nparams; i++) + { + png_free(png_ptr, info_ptr->pcal_params[i]); + info_ptr->pcal_params[i] = NULL; + } + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; + } +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* Free any iCCP entry */ + if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; + } +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ + if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) + { + if (num != -1) + { + if (info_ptr->splt_palettes) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + } + else + { + if (info_ptr->splt_palettes_num) + { + int i; + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + } + info_ptr->valid &= ~PNG_INFO_sPLT; + } + } +#endif + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_chunk.data) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + + if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) + { + if (num != -1) + { + if (info_ptr->unknown_chunks) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + } + else + { + int i; + + if (info_ptr->unknown_chunks_num) + { + for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } + } +#endif + +#ifdef PNG_hIST_SUPPORTED + /* Free any hIST entry */ + if ((mask & PNG_FREE_HIST) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; + } +#endif + + /* Free any PLTE entry that was internally allocated */ + if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) + { + png_zfree(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; + info_ptr->num_palette = 0; + } + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Free any image bits attached to the info structure */ + if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) + { + if (info_ptr->row_pointers) + { + int row; + for (row = 0; row < (int)info_ptr->height; row++) + { + png_free(png_ptr, info_ptr->row_pointers[row]); + info_ptr->row_pointers[row] = NULL; + } + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers = NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; + } +#endif + + if (num == -1) + info_ptr->free_me &= ~mask; + else + info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); +} + +/* This is an internal routine to free any memory that the info struct is + * pointing to before re-using it or freeing the struct itself. Recall + * that png_free() checks for NULL pointers for us. + */ +void /* PRIVATE */ +png_info_destroy(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_info_destroy"); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; + png_ptr->num_chunk_list = 0; + } +#endif + + png_info_init_3(&info_ptr, png_sizeof(png_info)); +} +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + return (png_ptr->io_ptr); +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't + * necessarily available. + */ +void PNGAPI +png_init_io(png_structp png_ptr, png_FILE_p fp) +{ + png_debug(1, "in png_init_io"); + + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = (png_voidp)fp; +} +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +png_charp PNGAPI +png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) +{ + static PNG_CONST char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (png_ptr == NULL) + return (NULL); + if (png_ptr->time_buffer == NULL) + { + png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* + png_sizeof(char))); + } + +#ifdef USE_FAR_KEYWORD + { + char near_time_buf[29]; + png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + png_memcpy(png_ptr->time_buffer, near_time_buf, + 29*png_sizeof(char)); + } +#else + png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); +#endif + return ((png_charp)png_ptr->time_buffer); +} +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +png_charp PNGAPI +png_get_copyright(png_structp png_ptr) +{ + png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ +#ifdef PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT +#else +#ifdef __STDC__ + return ((png_charp) PNG_STRING_NEWLINE \ + "libpng version 1.4.4 - September 23, 2010" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2010 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ + "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ + "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ + PNG_STRING_NEWLINE); +#else + return ((png_charp) "libpng version 1.4.4 - September 23, 2010\ + Copyright (c) 1998-2010 Glenn Randers-Pehrson\ + Copyright (c) 1996-1997 Andreas Dilger\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."); +#endif +#endif +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. + */ +png_charp PNGAPI +png_get_libpng_ver(png_structp png_ptr) +{ + /* Version of *.c files used when building libpng */ + png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); +} + +png_charp PNGAPI +png_get_header_ver(png_structp png_ptr) +{ + /* Version of *.h files used when building libpng */ + png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); +} + +png_charp PNGAPI +png_get_header_version(png_structp png_ptr) +{ + /* Returns longer string containing both version and date */ + png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ +#ifdef __STDC__ + return ((png_charp) PNG_HEADER_VERSION_STRING +#ifndef PNG_READ_SUPPORTED + " (NO READ SUPPORT)" +#endif + PNG_STRING_NEWLINE); +#else + return ((png_charp) PNG_HEADER_VERSION_STRING); +#endif +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) +{ + /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + int i; + png_bytep p; + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0) + return 0; + p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5; + for (i = png_ptr->num_chunk_list; i; i--, p -= 5) + if (!png_memcmp(chunk_name, p, 4)) + return ((int)*(p + 4)); + return 0; +} +#endif +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +#ifdef PNG_READ_SUPPORTED +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structp png_ptr) +{ + if (png_ptr == NULL) + return Z_STREAM_ERROR; + return (inflateReset(&png_ptr->zstream)); +} +#endif /* PNG_READ_SUPPORTED */ + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return((png_uint_32) PNG_LIBPNG_VER); +} + + + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#ifdef PNG_SIZE_T +/* Added at libpng version 1.2.6 */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); +png_size_t PNGAPI +png_convert_size(size_t size) +{ + if (size > (png_size_t)-1) + PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ + return ((png_size_t)size); +} +#endif /* PNG_SIZE_T */ + +/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_CHECK_cHRM_SUPPORTED + +/* + * Multiply two 32-bit numbers, V1 and V2, using 32-bit + * arithmetic, to produce a 64 bit result in the HI/LO words. + * + * A B + * x C D + * ------ + * AD || BD + * AC || CB || 0 + * + * where A and B are the high and low 16-bit words of V1, + * C and D are the 16-bit words of V2, AD is the product of + * A and D, and X || Y is (X << 16) + Y. +*/ + +void /* PRIVATE */ +png_64bit_product (long v1, long v2, unsigned long *hi_product, + unsigned long *lo_product) +{ + int a, b, c, d; + long lo, hi, x, y; + + a = (v1 >> 16) & 0xffff; + b = v1 & 0xffff; + c = (v2 >> 16) & 0xffff; + d = v2 & 0xffff; + + lo = b * d; /* BD */ + x = a * d + c * b; /* AD + CB */ + y = ((lo >> 16) & 0xffff) + x; + + lo = (lo & 0xffff) | ((y & 0xffff) << 16); + hi = (y >> 16) & 0xffff; + + hi += a * c; /* AC */ + + *hi_product = (unsigned long)hi; + *lo_product = (unsigned long)lo; +} + +int /* PRIVATE */ +png_check_cHRM_fixed(png_structp png_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + int ret = 1; + unsigned long xy_hi,xy_lo,yx_hi,yx_lo; + + png_debug(1, "in function png_check_cHRM_fixed"); + + if (png_ptr == NULL) + return 0; + + if (white_x < 0 || white_y <= 0 || + red_x < 0 || red_y < 0 || + green_x < 0 || green_y < 0 || + blue_x < 0 || blue_y < 0) + { + png_warning(png_ptr, + "Ignoring attempt to set negative chromaticity value"); + ret = 0; + } + if (white_x > (png_fixed_point) PNG_UINT_31_MAX || + white_y > (png_fixed_point) PNG_UINT_31_MAX || + red_x > (png_fixed_point) PNG_UINT_31_MAX || + red_y > (png_fixed_point) PNG_UINT_31_MAX || + green_x > (png_fixed_point) PNG_UINT_31_MAX || + green_y > (png_fixed_point) PNG_UINT_31_MAX || + blue_x > (png_fixed_point) PNG_UINT_31_MAX || + blue_y > (png_fixed_point) PNG_UINT_31_MAX ) + { + png_warning(png_ptr, + "Ignoring attempt to set chromaticity value exceeding 21474.83"); + ret = 0; + } + if (white_x > 100000L - white_y) + { + png_warning(png_ptr, "Invalid cHRM white point"); + ret = 0; + } + if (red_x > 100000L - red_y) + { + png_warning(png_ptr, "Invalid cHRM red point"); + ret = 0; + } + if (green_x > 100000L - green_y) + { + png_warning(png_ptr, "Invalid cHRM green point"); + ret = 0; + } + if (blue_x > 100000L - blue_y) + { + png_warning(png_ptr, "Invalid cHRM blue point"); + ret = 0; + } + + png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo); + png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo); + + if (xy_hi == yx_hi && xy_lo == yx_lo) + { + png_warning(png_ptr, + "Ignoring attempt to set cHRM RGB triangle with zero area"); + ret = 0; + } + + return ret; +} +#endif /* PNG_CHECK_cHRM_SUPPORTED */ +#endif /* PNG_cHRM_SUPPORTED */ + +void /* PRIVATE */ +png_check_IHDR(png_structp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + int error = 0; + + /* Check for width and height valid values */ + if (width == 0) + { + png_warning(png_ptr, "Image width is zero in IHDR"); + error = 1; + } + + if (height == 0) + { + png_warning(png_ptr, "Image height is zero in IHDR"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX) +#else + if (width > PNG_USER_WIDTH_MAX) +#endif + { + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX) +#else + if (height > PNG_USER_HEIGHT_MAX) +#endif + { + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } + + if (width > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image width in IHDR"); + error = 1; + } + + if ( height > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image height in IHDR"); + error = 1; + } + + if ( width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + png_warning(png_ptr, "Width is too large for libpng to process pixels"); + + /* Check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + { + png_warning(png_ptr, "Invalid bit depth in IHDR"); + error = 1; + } + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + { + png_warning(png_ptr, "Invalid color type in IHDR"); + error = 1; + } + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + { + png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); + error = 1; + } + + if (interlace_type >= PNG_INTERLACE_LAST) + { + png_warning(png_ptr, "Unknown interlace method in IHDR"); + error = 1; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Unknown compression method in IHDR"); + error = 1; + } + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && + png_ptr->mng_features_permitted) + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + + if (filter_type != PNG_FILTER_TYPE_BASE) + { + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } + + if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) + { + png_warning(png_ptr, "Invalid filter method in IHDR"); + error = 1; + } + } + +#else + if (filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } +#endif + + if (error == 1) + png_error(png_ptr, "Invalid IHDR data"); +} +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ diff --git a/libs/png/png.h b/thirdparty/libpng/png.h old mode 100755 new mode 100644 similarity index 100% rename from libs/png/png.h rename to thirdparty/libpng/png.h diff --git a/libs/png/pngconf.h b/thirdparty/libpng/pngconf.h old mode 100755 new mode 100644 similarity index 100% rename from libs/png/pngconf.h rename to thirdparty/libpng/pngconf.h diff --git a/thirdparty/libpng/pngerror.c b/thirdparty/libpng/pngerror.c new file mode 100644 index 00000000..633eae29 --- /dev/null +++ b/thirdparty/libpng/pngerror.c @@ -0,0 +1,402 @@ + +/* pngerror.c - stub functions for i/o and memory allocation + * + * Last changed in libpng 1.4.0 [January 3, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#include "pngpriv.h" + +static void /* PRIVATE */ +png_default_error PNGARG((png_structp png_ptr, + png_const_charp error_message)) PNG_NORETURN; +#ifdef PNG_WARNINGS_SUPPORTED +static void /* PRIVATE */ +png_default_warning PNGARG((png_structp png_ptr, + png_const_charp warning_message)); +#endif /* PNG_WARNINGS_SUPPORTED */ + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +#ifdef PNG_ERROR_TEXT_SUPPORTED +void PNGAPI +png_error(png_structp png_ptr, png_const_charp error_message) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr != NULL) + { + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') + break; + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + else + error_message += offset; + } + else + { + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } + } + } + } +#endif + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_ptr, error_message); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, error_message); +} +#else +void PNGAPI +png_err(png_structp png_ptr) +{ + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_ptr, '\0'); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, '\0'); +} +#endif /* PNG_ERROR_TEXT_SUPPORTED */ + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_structp png_ptr, png_const_charp warning_message) +{ + int offset = 0; + if (png_ptr != NULL) + { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) +#endif + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') + break; + } + } + } + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_ptr, warning_message + offset); + else + png_default_warning(png_ptr, warning_message + offset); +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_benign_error(png_structp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); +} +#endif + +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * this is used to prefix the message. The message is limited in length + * to 63 bytes, the name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +static PNG_CONST char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +#define PNG_MAX_ERROR_TEXT 64 +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) +static void /* PRIVATE */ +png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp + error_message) +{ + int iout = 0, iin = 0; + + while (iin < 4) + { + int c = png_ptr->chunk_name[iin++]; + if (isnonalpha(c)) + { + buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; + } + else + { + buffer[iout++] = (png_byte)c; + } + } + + if (error_message == NULL) + buffer[iout] = '\0'; + else + { + buffer[iout++] = ':'; + buffer[iout++] = ' '; + png_memcpy(buffer + iout, error_message, PNG_MAX_ERROR_TEXT); + buffer[iout + PNG_MAX_ERROR_TEXT - 1] = '\0'; + } +} + +#ifdef PNG_READ_SUPPORTED +void PNGAPI +png_chunk_error(png_structp png_ptr, png_const_charp error_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_error(png_ptr, error_message); + else + { + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); + } +} +#endif /* PNG_READ_SUPPORTED */ +#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ + +#ifdef PNG_WARNINGS_SUPPORTED +void PNGAPI +png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_warning(png_ptr, warning_message); + else + { + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); + } +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +#ifdef PNG_READ_SUPPORTED +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_chunk_warning(png_ptr, error_message); + else + png_chunk_error(png_ptr, error_message); +} +#endif +#endif /* PNG_READ_SUPPORTED */ + +#ifdef PNG_SETJMP_SUPPORTED +/* This API only exists if ANSI-C style error handling is used, + * otherwise it is necessary for png_default_error to be overridden. + */ +jmp_buf* PNGAPI +png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn, + size_t jmp_buf_size) +{ + if (png_ptr == NULL || jmp_buf_size != png_sizeof(jmp_buf)) + return NULL; + + png_ptr->longjmp_fn = longjmp_fn; + return &png_ptr->jmpbuf; +} +#endif + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void /* PRIVATE */ +png_default_error(png_structp png_ptr, png_const_charp error_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { + error_number[offset] = error_message[offset + 1]; + if (error_message[offset] == ' ') + break; + } + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +#endif + { + fprintf(stderr, "libpng error: %s", error_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#endif + +#ifdef PNG_SETJMP_SUPPORTED + if (png_ptr && png_ptr->longjmp_fn) + { +# ifdef USE_FAR_KEYWORD + { + jmp_buf jmpbuf; + png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf)); + png_ptr->longjmp_fn(jmpbuf, 1); + } +# else + png_ptr->longjmp_fn(png_ptr->jmpbuf, 1); +# endif + } +#endif + /* Here if not setjmp support or if png_ptr is null. */ + PNG_ABORT(); +#ifndef PNG_CONSOLE_IO_SUPPORTED + error_message = error_message; /* Make compiler happy */ +#endif +} + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_structp png_ptr, png_const_charp warning_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == PNG_LITERAL_SHARP) + { + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') + break; + } + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +# endif + { + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + warning_message = warning_message; /* Make compiler happy */ +#endif + png_ptr = png_ptr; /* Make compiler happy */ +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) + */ +void PNGAPI +png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + return ((png_voidp)png_ptr->error_ptr); +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void PNGAPI +png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) +{ + if (png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngget.c b/thirdparty/libpng/pngget.c new file mode 100644 index 00000000..abe721bd --- /dev/null +++ b/thirdparty/libpng/pngget.c @@ -0,0 +1,925 @@ + +/* pngget.c - retrieval of values from info struct + * + * Last changed in libpng 1.4.2 [May 6, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#include "pngpriv.h" + +png_uint_32 PNGAPI +png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->valid & flag); + + else + return(0); +} + +png_size_t PNGAPI +png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->rowbytes); + + else + return(0); +} + +#ifdef PNG_INFO_IMAGE_SUPPORTED +png_bytepp PNGAPI +png_get_rows(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->row_pointers); + + else + return(0); +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->width; + + return (0); +} + +png_uint_32 PNGAPI +png_get_image_height(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->height; + + return (0); +} + +png_byte PNGAPI +png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->bit_depth; + + return (0); +} + +png_byte PNGAPI +png_get_color_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->color_type; + + return (0); +} + +png_byte PNGAPI +png_get_filter_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->filter_type; + + return (0); +} + +png_byte PNGAPI +png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->interlace_type; + + return (0); +} + +png_byte PNGAPI +png_get_compression_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->compression_type; + + return (0); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); + + if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + + else + return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); + + if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + + else + return (info_ptr->y_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); + + if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER || + info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) + return (0); + + else + return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) + { + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_pHYs_SUPPORTED + + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); + + if (info_ptr->x_pixels_per_unit == 0) + return ((float)0.0); + + else + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); + } +#else + return (0.0); +#endif + return ((float)0.0); +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#ifdef PNG_oFFs_SUPPORTED + + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + + else + return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + +#ifdef PNG_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + + else + return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + +#ifdef PNG_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + + else + return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + +#ifdef PNG_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + + if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + + else + return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +float PNGAPI +png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_x_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +float PNGAPI +png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_y_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + if (*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + return (retval); +} +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +png_byte PNGAPI +png_get_channels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->channels); + else + return (0); +} + +png_bytep PNGAPI +png_get_signature(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->signature); + else + return (NULL); +} + +#ifdef PNG_bKGD_SUPPORTED +png_uint_32 PNGAPI +png_get_bKGD(png_structp png_ptr, png_infop info_ptr, + png_color_16p *background) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) + && background != NULL) + { + png_debug1(1, "in %s retrieval function", "bKGD"); + + *background = &(info_ptr->background); + return (PNG_INFO_bKGD); + } + return (0); +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_structp png_ptr, png_infop info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (white_x != NULL) + *white_x = (double)info_ptr->x_white; + if (white_y != NULL) + *white_y = (double)info_ptr->y_white; + if (red_x != NULL) + *red_x = (double)info_ptr->x_red; + if (red_y != NULL) + *red_y = (double)info_ptr->y_red; + if (green_x != NULL) + *green_x = (double)info_ptr->x_green; + if (green_y != NULL) + *green_y = (double)info_ptr->y_green; + if (blue_x != NULL) + *blue_x = (double)info_ptr->x_blue; + if (blue_y != NULL) + *blue_y = (double)info_ptr->y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + if (white_x != NULL) + *white_x = info_ptr->int_x_white; + if (white_y != NULL) + *white_y = info_ptr->int_y_white; + if (red_x != NULL) + *red_x = info_ptr->int_x_red; + if (red_y != NULL) + *red_y = info_ptr->int_y_red; + if (green_x != NULL) + *green_x = info_ptr->int_x_green; + if (green_y != NULL) + *green_y = info_ptr->int_y_green; + if (blue_x != NULL) + *blue_x = info_ptr->int_x_blue; + if (blue_y != NULL) + *blue_y = info_ptr->int_y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && file_gamma != NULL) + { + *file_gamma = (double)info_ptr->gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *int_file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && int_file_gamma != NULL) + { + *int_file_gamma = info_ptr->int_gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#endif + +#ifdef PNG_sRGB_SUPPORTED +png_uint_32 PNGAPI +png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) +{ + png_debug1(1, "in %s retrieval function", "sRGB"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) + && file_srgb_intent != NULL) + { + *file_srgb_intent = (int)info_ptr->srgb_intent; + return (PNG_INFO_sRGB); + } + return (0); +} +#endif + +#ifdef PNG_iCCP_SUPPORTED +png_uint_32 PNGAPI +png_get_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen) +{ + png_debug1(1, "in %s retrieval function", "iCCP"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) + && name != NULL && profile != NULL && proflen != NULL) + { + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + /* Compression_type is a dummy so the API won't have to change + * if we introduce multiple compression types later. + */ + *proflen = (int)info_ptr->iccp_proflen; + *compression_type = (int)info_ptr->iccp_compression; + return (PNG_INFO_iCCP); + } + return (0); +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +png_uint_32 PNGAPI +png_get_sPLT(png_structp png_ptr, png_infop info_ptr, + png_sPLT_tpp spalettes) +{ + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + { + *spalettes = info_ptr->splt_palettes; + return ((png_uint_32)info_ptr->splt_palettes_num); + } + return (0); +} +#endif + +#ifdef PNG_hIST_SUPPORTED +png_uint_32 PNGAPI +png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) +{ + png_debug1(1, "in %s retrieval function", "hIST"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) + && hist != NULL) + { + *hist = info_ptr->hist; + return (PNG_INFO_hIST); + } + return (0); +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) + +{ + png_debug1(1, "in %s retrieval function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL || width == NULL || + height == NULL || bit_depth == NULL || color_type == NULL) + return (0); + + *width = info_ptr->width; + *height = info_ptr->height; + *bit_depth = info_ptr->bit_depth; + *color_type = info_ptr->color_type; + + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* This is redundant if we can be sure that the info_ptr values were all + * assigned in png_set_IHDR(). We do the check anyhow in case an + * application has ignored our advice not to mess with the members + * of info_ptr directly. + */ + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + return (1); +} + +#ifdef PNG_oFFs_SUPPORTED +png_uint_32 PNGAPI +png_get_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + png_debug1(1, "in %s retrieval function", "oFFs"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) + && offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return (PNG_INFO_oFFs); + } + return (0); +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +png_uint_32 PNGAPI +png_get_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + png_debug1(1, "in %s retrieval function", "pCAL"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) + && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return (PNG_INFO_pCAL); + } + return (0); +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_structp png_ptr, png_infop info_ptr, + int *unit, double *width, double *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_pixel_width; + *height = info_ptr->scal_pixel_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#endif +#endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs)) + { + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + return (retval); +} +#endif + +png_uint_32 PNGAPI +png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, + int *num_palette) +{ + png_debug1(1, "in %s retrieval function", "PLTE"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) + && palette != NULL) + { + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d", *num_palette); + return (PNG_INFO_PLTE); + } + return (0); +} + +#ifdef PNG_sBIT_SUPPORTED +png_uint_32 PNGAPI +png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) +{ + png_debug1(1, "in %s retrieval function", "sBIT"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) + && sig_bit != NULL) + { + *sig_bit = &(info_ptr->sig_bit); + return (PNG_INFO_sBIT); + } + return (0); +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +png_uint_32 PNGAPI +png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, + int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in %s retrieval function", + (png_ptr->chunk_name[0] == '\0' ? "text" + : (png_const_charp)png_ptr->chunk_name)); + + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + + if (num_text != NULL) + *num_text = info_ptr->num_text; + + return ((png_uint_32)info_ptr->num_text); + } + if (num_text != NULL) + *num_text = 0; + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +png_uint_32 PNGAPI +png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) +{ + png_debug1(1, "in %s retrieval function", "tIME"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) + && mod_time != NULL) + { + *mod_time = &(info_ptr->mod_time); + return (PNG_INFO_tIME); + } + return (0); +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +png_uint_32 PNGAPI +png_get_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) +{ + png_uint_32 retval = 0; + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_debug1(1, "in %s retrieval function", "tRNS"); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans_alpha != NULL) + { + *trans_alpha = info_ptr->trans_alpha; + retval |= PNG_INFO_tRNS; + } + + if (trans_color != NULL) + *trans_color = &(info_ptr->trans_color); + } + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_color != NULL) + { + *trans_color = &(info_ptr->trans_color); + retval |= PNG_INFO_tRNS; + } + + if (trans_alpha != NULL) + *trans_alpha = NULL; + } + if (num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + return (retval); +} +#endif + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +png_uint_32 PNGAPI +png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + { + *unknowns = info_ptr->unknown_chunks; + return ((png_uint_32)info_ptr->unknown_chunks_num); + } + return (0); +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +png_byte PNGAPI +png_get_rgb_to_gray_status (png_structp png_ptr) +{ + return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +png_voidp PNGAPI +png_get_user_chunk_ptr(png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_chunk_ptr : NULL); +} +#endif + +png_size_t PNGAPI +png_get_compression_buffer_size(png_structp png_ptr) +{ + return (png_ptr ? png_ptr->zbuf_size : 0L); +} + + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* These functions were added to libpng 1.2.6 and were enabled + * by default in libpng-1.4.0 */ +png_uint_32 PNGAPI +png_get_user_width_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_width_max : 0); +} +png_uint_32 PNGAPI +png_get_user_height_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_height_max : 0); +} +/* This function was added to libpng 1.4.0 */ +png_uint_32 PNGAPI +png_get_chunk_cache_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_chunk_cache_max : 0); +} +/* This function was added to libpng 1.4.1 */ +png_alloc_size_t PNGAPI +png_get_chunk_malloc_max (png_structp png_ptr) +{ + return (png_ptr? + png_ptr->user_chunk_malloc_max : 0); +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +/* These functions were added to libpng 1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +png_uint_32 PNGAPI +png_get_io_state (png_structp png_ptr) +{ + return png_ptr->io_state; +} + +png_bytep PNGAPI +png_get_io_chunk_name (png_structp png_ptr) +{ + return png_ptr->chunk_name; +} +#endif /* ?PNG_IO_STATE_SUPPORTED */ + +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngmem.c b/thirdparty/libpng/pngmem.c new file mode 100644 index 00000000..c8a3f6f5 --- /dev/null +++ b/thirdparty/libpng/pngmem.c @@ -0,0 +1,611 @@ + +/* pngmem.c - stub functions for memory allocation + * + * Last changed in libpng 1.4.2 [May 6, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#include "pngpriv.h" + +/* Borland DOS special memory handler */ +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* If you change this, be sure to change the one in png.h also */ + +/* Allocate memory for a png_struct. The malloc and memset can be replaced + by a single call to calloc() if this is thought to improve performance. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, NULL, NULL)); +} + +/* Alternate version of png_create_struct, for use with user-defined malloc. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = png_sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = png_sizeof(png_struct); + else + return (png_get_copyright(NULL)); + +#ifdef PNG_USER_MEM_SUPPORTED + if (malloc_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size); + } + else +#endif /* PNG_USER_MEM_SUPPORTED */ + struct_ptr = (png_voidp)farmalloc(size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, NULL, NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ + farfree (struct_ptr); + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * Borland seems to have a problem in DOS mode for exactly 64K. + * It gives you a segment with an offset of 8 (perhaps to store its + * memory stuff). zlib doesn't like this at all, so we have to + * detect and deal with it. This code should not be needed in + * Windows or OS/2 modes, and only in 16 bit mode. This code has + * been updated by Alexander Lehmann for version 0.89 to waste less + * memory. + * + * Note that we can't use png_size_t for the "size" declaration, + * since on some systems a png_size_t is a 16-bit quantity, and as a + * result, we would be truncating potentially larger memory requests + * (which should cause a fatal error) and introducing major problems. + */ +png_voidp PNGAPI +png_calloc(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ret; + + ret = (png_malloc(png_ptr, size)); + if (ret != NULL) + png_memset(ret,0,(png_size_t)size); + return (ret); +} + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ret; + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->malloc_fn != NULL) + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + else + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory"); + return (ret); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + { + png_warning(png_ptr, "Cannot Allocate > 64K"); + ret = NULL; + } + else +#endif + + if (size != (size_t)size) + ret = NULL; + else if (size == (png_uint_32)65536L) + { + if (png_ptr->offset_table == NULL) + { + /* Try to see if we need to do any of this fancy stuff */ + ret = farmalloc(size); + if (ret == NULL || ((png_size_t)ret & 0xffff)) + { + int num_blocks; + png_uint_32 total_size; + png_bytep table; + int i; + png_byte huge * hptr; + + if (ret != NULL) + { + farfree(ret); + ret = NULL; + } + + if (png_ptr->zlib_window_bits > 14) + num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); + else + num_blocks = 1; + if (png_ptr->zlib_mem_level >= 7) + num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); + else + num_blocks++; + + total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; + + table = farmalloc(total_size); + + if (table == NULL) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out Of Memory"); /* Note "O", "M" */ + else + png_warning(png_ptr, "Out Of Memory"); +#endif + return (NULL); + } + + if ((png_size_t)table & 0xfff0) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, + "Farmalloc didn't return normalized pointer"); + else + png_warning(png_ptr, + "Farmalloc didn't return normalized pointer"); +#endif + return (NULL); + } + + png_ptr->offset_table = table; + png_ptr->offset_table_ptr = farmalloc(num_blocks * + png_sizeof(png_bytep)); + + if (png_ptr->offset_table_ptr == NULL) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out Of memory"); /* Note "O", "m" */ + else + png_warning(png_ptr, "Out Of memory"); +#endif + return (NULL); + } + + hptr = (png_byte huge *)table; + if ((png_size_t)hptr & 0xf) + { + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ + } + for (i = 0; i < num_blocks; i++) + { + png_ptr->offset_table_ptr[i] = (png_bytep)hptr; + hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ + } + + png_ptr->offset_table_number = num_blocks; + png_ptr->offset_table_count = 0; + png_ptr->offset_table_count_free = 0; + } + } + + if (png_ptr->offset_table_count >= png_ptr->offset_table_number) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory"); /* Note "o" and "M" */ + else + png_warning(png_ptr, "Out of Memory"); +#endif + return (NULL); + } + + ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; + } + else + ret = farmalloc(size); + +#ifndef PNG_USER_MEM_SUPPORTED + if (ret == NULL) + { + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory"); /* Note "o" and "m" */ + else + png_warning(png_ptr, "Out of memory"); /* Note "o" and "m" */ + } +#endif + + return (ret); +} + +/* Free a pointer allocated by png_malloc(). In the default + * configuration, png_ptr is not used, but is passed in case it + * is needed. If ptr is NULL, return without taking any action. + */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else + png_free_default(png_ptr, ptr); +} + +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || ptr == NULL) + return; + + if (png_ptr->offset_table != NULL) + { + int i; + + for (i = 0; i < png_ptr->offset_table_count; i++) + { + if (ptr == png_ptr->offset_table_ptr[i]) + { + ptr = NULL; + png_ptr->offset_table_count_free++; + break; + } + } + if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) + { + farfree(png_ptr->offset_table); + farfree(png_ptr->offset_table_ptr); + png_ptr->offset_table = NULL; + png_ptr->offset_table_ptr = NULL; + } + } + + if (ptr != NULL) + { + farfree(ptr); + } +} + +#else /* Not the Borland DOS special memory handler */ + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, NULL, NULL)); +} + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = png_sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = png_sizeof(png_struct); + else + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if (malloc_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); + } +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + struct_ptr = (png_voidp)farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + struct_ptr = (png_voidp)halloc(size, 1); +# else + struct_ptr = (png_voidp)malloc(size); +# endif +#endif + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, NULL, NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(struct_ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(struct_ptr); +# else + free(struct_ptr); +# endif +#endif + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + */ + +png_voidp PNGAPI +png_calloc(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ret; + + ret = (png_malloc(png_ptr, size)); + if (ret != NULL) + png_memset(ret,0,(png_size_t)size); + return (ret); +} + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ret; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr == NULL || size == 0) + return (NULL); + + if (png_ptr->malloc_fn != NULL) + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + else + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory"); + return (ret); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Cannot Allocate > 64K"); + else +#endif + return NULL; + } +#endif + + /* Check for overflow */ +#if defined(__TURBOC__) && !defined(__FLAT__) + if (size != (unsigned long)size) + ret = NULL; + else + ret = farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + if (size != (unsigned long)size) + ret = NULL; + else + ret = halloc(size, 1); +# else + if (size != (size_t)size) + ret = NULL; + else + ret = malloc((size_t)size); +# endif +#endif + +#ifndef PNG_USER_MEM_SUPPORTED + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory"); +#endif + + return (ret); +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + * without taking any action. + */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else + png_free_default(png_ptr, ptr); +} +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(ptr); +# else + free(ptr); +# endif +#endif +} + +#endif /* Not Borland DOS special memory handler */ + +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will set up png_malloc() to issue a png_warning and return NULL + * instead of issuing a png_error, if it fails to allocate the requested + * memory. + */ +png_voidp PNGAPI +png_malloc_warn(png_structp png_ptr, png_alloc_size_t size) +{ + png_voidp ptr; + png_uint_32 save_flags; + if (png_ptr == NULL) + return (NULL); + + save_flags = png_ptr->flags; + png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; + ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); + png_ptr->flags=save_flags; + return(ptr); +} + + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + if (png_ptr != NULL) + { + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; + } +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + return ((png_voidp)png_ptr->mem_ptr); +} +#endif /* PNG_USER_MEM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngpread.c b/thirdparty/libpng/pngpread.c new file mode 100644 index 00000000..e33b4286 --- /dev/null +++ b/thirdparty/libpng/pngpread.c @@ -0,0 +1,1765 @@ + +/* pngpread.c - read a png file in push mode + * + * Last changed in libpng 1.4.3 [June 26, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +#include "pngpriv.h" + +/* Push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_SKIP_MODE 3 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +void PNGAPI +png_process_data(png_structp png_ptr, png_infop info_ptr, + png_bytep buffer, png_size_t buffer_size) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr == NULL) + return; + + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } + +#ifdef PNG_READ_tEXt_SUPPORTED + case PNG_READ_tEXt_MODE: + { + png_push_read_tEXt(png_ptr, info_ptr); + break; + } + +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + case PNG_READ_zTXt_MODE: + { + png_push_read_zTXt(png_ptr, info_ptr); + break; + } + +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + case PNG_READ_iTXt_MODE: + { + png_push_read_iTXt(png_ptr, info_ptr); + break; + } + +#endif + case PNG_SKIP_MODE: + { + png_push_crc_finish(png_ptr); + break; + } + + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structp png_ptr, png_infop info_ptr) +{ + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) +{ + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#ifdef PNG_READ_bKGD_SUPPORTED + PNG_bKGD; +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + PNG_cHRM; +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + PNG_gAMA; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + PNG_hIST; +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + PNG_iCCP; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + PNG_iTXt; +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + PNG_oFFs; +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + PNG_pCAL; +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + PNG_pHYs; +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + PNG_sBIT; +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + PNG_sCAL; +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + PNG_sRGB; +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + PNG_sPLT; +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + PNG_tEXt; +#endif +#ifdef PNG_READ_tIME_SUPPORTED + PNG_tIME; +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + PNG_tRNS; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + PNG_zTXt; +#endif + + /* First we make sure we have enough data for the 4 byte chunk name + * and the 4 byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4 byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + if (png_ptr->mode & PNG_AFTER_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + { + if (png_ptr->push_length != 13) + png_error(png_ptr, "Invalid IHDR length"); + + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + } + } + +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + { + if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if (png_ptr->push_length == 0) + return; + + if (png_ptr->mode & PNG_AFTER_IDAT) + png_benign_error(png_ptr, "Too many IDATs found"); + } + + png_ptr->idat_size = png_ptr->push_length; + png_ptr->mode |= PNG_HAVE_IDAT; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_bKGD_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif + else + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void /* PRIVATE */ +png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) +{ + png_ptr->process_mode = PNG_SKIP_MODE; + png_ptr->skip_length = skip; +} + +void /* PRIVATE */ +png_push_crc_finish(png_structp png_ptr) +{ + if (png_ptr->skip_length && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->skip_length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->skip_length) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } +} + +void PNGAPI +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) +{ + png_bytep ptr; + + if (png_ptr == NULL) + return; + + ptr = buffer; + if (png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + else + save_size = png_ptr->save_buffer_size; + + png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + + else + save_size = png_ptr->current_buffer_size; + + png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structp png_ptr) +{ + if (png_ptr->save_buffer_size) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + png_size_t i, istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + png_size_t new_max; + png_bytep old_buffer; + + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } + + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, + (png_size_t)new_max); + if (png_ptr->save_buffer == NULL) + { + png_free(png_ptr, old_buffer); + png_error(png_ptr, "Insufficient memory for save_buffer"); + } + png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structp png_ptr) +{ + PNG_IDAT; + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_error(png_ptr, "Not enough compressed data"); + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + if (png_ptr->idat_size && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + + /* Check for overflow */ + if ((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->idat_size && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + + /* Check for overflow */ + if ((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->idat_size) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + /* The caller checks for a non-zero buffer length. */ + if (!(buffer_length > 0) || buffer == NULL) + png_error(png_ptr, "No IDAT data (internal error)"); + + /* This routine must process all the data it has been given + * before returning, calling the row callback as required to + * handle the uncompressed results. + */ + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = (uInt)buffer_length; + + /* Keep going until the decompressed data is all processed + * or the stream marked as finished. + */ + while (png_ptr->zstream.avail_in > 0 && + !(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + { + int ret; + + /* We have data for zlib, but we must check that zlib + * has somewhere to put the results. It doesn't matter + * if we don't expect any results -- it may be the input + * data is just the LZ end code. + */ + if (!(png_ptr->zstream.avail_out > 0)) + { + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + } + + /* Using Z_SYNC_FLUSH here means that an unterminated + * LZ stream can still be handled (a stream with a missing + * end code), otherwise (Z_NO_FLUSH) a future zlib + * implementation might defer output and, therefore, + * change the current behavior. (See comments in inflate.c + * for why this doesn't happen at present with zlib 1.2.5.) + */ + ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); + + /* Check for any failure before proceeding. */ + if (ret != Z_OK && ret != Z_STREAM_END) + { + /* Terminate the decompression. */ + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + + /* This may be a truncated stream (missing or + * damaged end code). Treat that as a warning. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + png_warning(png_ptr, "Truncated compressed data in IDAT"); + else + png_error(png_ptr, "Decompression error in IDAT"); + + /* Skip the check on unprocessed input */ + return; + } + + /* Did inflate output any data? */ + if (png_ptr->zstream.next_out != png_ptr->row_buf) + { + /* Is this unexpected data after the last row? + * If it is, artificially terminate the LZ output + * here. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + { + /* Extra data. */ + png_warning(png_ptr, "Extra compressed data in IDAT"); + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + /* Do no more processing; skip the unprocessed + * input check below. + */ + return; + } + + /* Do we have a complete row? */ + if (png_ptr->zstream.avail_out == 0) + png_push_process_row(png_ptr); + } + + /* And check for the end of the stream. */ + if (ret == Z_STREAM_END) + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + } + + /* All the data should have been processed, if anything + * is left at this point we have bytes of IDAT data + * after the zlib end code. + */ + if (png_ptr->zstream.avail_in > 0) + png_warning(png_ptr, "Extra compression data"); +} + +void /* PRIVATE */ +png_push_process_row(png_structp png_ptr) +{ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) +/* old interface (pre-1.0.9): + png_do_read_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ + } + + if (png_ptr->pass == 2) /* Pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 2) /* Skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 2: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 3: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 4: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Pass 5 might be empty */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 5: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Skip top generated row */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + + if (png_ptr->pass != 6) + break; + + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structp png_ptr) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ + + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset(png_ptr->prev_row, 0, + png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass > 7) + png_ptr->pass--; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if (png_ptr->transformations & PNG_INTERLACE) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +} + +#ifdef PNG_READ_tEXt_SUPPORTED +void /* PRIVATE */ +png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place tEXt"); + info_ptr = info_ptr; /* To quiet some compiler warnings */ + } + +#ifdef PNG_MAX_MALLOC_64K + png_ptr->skip_length = 0; /* This may not be necessary */ + + if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + png_ptr->skip_length = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_size_t)(length + 1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_tEXt_MODE; +} + +void /* PRIVATE */ +png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + + else + text_size = png_ptr->current_text_left; + + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp text; + png_charp key; + int ret; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + +#ifdef PNG_MAX_MALLOC_64K + if (png_ptr->skip_length) + return; +#endif + + key = png_ptr->current_text; + + for (text = key; *text; text++) + /* Empty loop */ ; + + if (text < key + png_ptr->current_text_size) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, + png_sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; +#endif + text_ptr->text = text; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + png_ptr->current_text = NULL; + + if (ret) + png_warning(png_ptr, "Insufficient memory to store text chunk"); + } +} +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +void /* PRIVATE */ +png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place zTXt"); + info_ptr = info_ptr; /* To quiet some compiler warnings */ + } + +#ifdef PNG_MAX_MALLOC_64K + /* We can't handle zTXt chunks > 64K, since we don't have enough space + * to be able to store the uncompressed data. Actually, the threshold + * is probably around 32K, but it isn't as definite as 64K is. + */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "zTXt chunk too large to fit in memory"); + png_push_crc_skip(png_ptr, length); + return; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_size_t)(length + 1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_zTXt_MODE; +} + +void /* PRIVATE */ +png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + + else + text_size = png_ptr->current_text_left; + + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp text; + png_charp key; + int ret; + png_size_t text_size, key_size; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + + key = png_ptr->current_text; + + for (text = key; *text; text++) + /* Empty loop */ ; + + /* zTXt can't have zero text */ + if (text >= key + png_ptr->current_text_size) + { + png_ptr->current_text = NULL; + png_free(png_ptr, key); + return; + } + + text++; + + if (*text != PNG_TEXT_COMPRESSION_zTXt) /* Check compression byte */ + { + png_ptr->current_text = NULL; + png_free(png_ptr, key); + return; + } + + text++; + + png_ptr->zstream.next_in = (png_bytep )text; + png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size - + (text - key)); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + key_size = text - key; + text_size = 0; + text = NULL; + ret = Z_STREAM_END; + + while (png_ptr->zstream.avail_in) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + png_ptr->current_text = NULL; + png_free(png_ptr, key); + png_free(png_ptr, text); + return; + } + if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END) + { + if (text == NULL) + { + text = (png_charp)png_malloc(png_ptr, + (png_ptr->zbuf_size + - png_ptr->zstream.avail_out + key_size + 1)); + + png_memcpy(text + key_size, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + + png_memcpy(text, key, key_size); + + text_size = key_size + png_ptr->zbuf_size - + png_ptr->zstream.avail_out; + + *(text + text_size) = '\0'; + } + else + { + png_charp tmp; + + tmp = text; + text = (png_charp)png_malloc(png_ptr, text_size + + (png_ptr->zbuf_size + - png_ptr->zstream.avail_out + 1)); + + png_memcpy(text, tmp, text_size); + png_free(png_ptr, tmp); + + png_memcpy(text + text_size, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + + text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; + *(text + text_size) = '\0'; + } + if (ret != Z_STREAM_END) + { + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else + { + break; + } + + if (ret == Z_STREAM_END) + break; + } + + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + if (ret != Z_STREAM_END) + { + png_ptr->current_text = NULL; + png_free(png_ptr, key); + png_free(png_ptr, text); + return; + } + + png_ptr->current_text = NULL; + png_free(png_ptr, key); + key = text; + text += key_size; + + text_ptr = (png_textp)png_malloc(png_ptr, + png_sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; +#endif + text_ptr->text = text; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + + if (ret) + png_warning(png_ptr, "Insufficient memory to store text chunk"); + } +} +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED +void /* PRIVATE */ +png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place iTXt"); + info_ptr = info_ptr; /* To quiet some compiler warnings */ + } + +#ifdef PNG_MAX_MALLOC_64K + png_ptr->skip_length = 0; /* This may not be necessary */ + + if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ + { + png_warning(png_ptr, "iTXt chunk too large to fit in memory"); + png_ptr->skip_length = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_size_t)(length + 1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_iTXt_MODE; +} + +void /* PRIVATE */ +png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) +{ + + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + + else + text_size = png_ptr->current_text_left; + + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp key; + int comp_flag; + png_charp lang; + png_charp lang_key; + png_charp text; + int ret; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + +#ifdef PNG_MAX_MALLOC_64K + if (png_ptr->skip_length) + return; +#endif + + key = png_ptr->current_text; + + for (lang = key; *lang; lang++) + /* Empty loop */ ; + + if (lang < key + png_ptr->current_text_size - 3) + lang++; + + comp_flag = *lang++; + lang++; /* Skip comp_type, always zero */ + + for (lang_key = lang; *lang_key; lang_key++) + /* Empty loop */ ; + + lang_key++; /* Skip NUL separator */ + + text=lang_key; + + if (lang_key < key + png_ptr->current_text_size - 1) + { + for (; *text; text++) + /* Empty loop */ ; + } + + if (text < key + png_ptr->current_text_size) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, + png_sizeof(png_text)); + + text_ptr->compression = comp_flag + 2; + text_ptr->key = key; + text_ptr->lang = lang; + text_ptr->lang_key = lang_key; + text_ptr->text = text; + text_ptr->text_length = 0; + text_ptr->itxt_length = png_strlen(text); + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_ptr->current_text = NULL; + + png_free(png_ptr, text_ptr); + if (ret) + png_warning(png_ptr, "Insufficient memory to store iTXt chunk"); + } +} +#endif + +/* This function is called when we haven't found a handler for this + * chunk. If there isn't a problem with the chunk itself (ie a bad chunk + * name or a critical chunk), the chunk is (currently) silently ignored. + */ +void /* PRIVATE */ +png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + png_uint_32 skip = 0; + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + + info_ptr = info_ptr; /* To quiet some compiler warnings */ + } + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + png_memcpy((png_charp)png_ptr->unknown_chunk.name, + (png_charp)png_ptr->chunk_name, + png_sizeof(png_ptr->unknown_chunk.name)); + png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name) - 1] + = '\0'; + + png_ptr->unknown_chunk.size = (png_size_t)length; + + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + + else + { + png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, + (png_size_t)length); + png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); + } + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + if (png_ptr->read_user_chunk_fn != NULL) + { + /* Callback to user unknown chunk handler */ + int ret; + ret = (*(png_ptr->read_user_chunk_fn)) + (png_ptr, &png_ptr->unknown_chunk); + + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + + if (ret == 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS) + png_chunk_error(png_ptr, "unknown critical chunk"); + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + } + } + + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + + else +#endif + skip=length; + png_push_crc_skip(png_ptr, skip); +} + +void /* PRIVATE */ +png_push_have_info(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +void PNGAPI +png_progressive_combine_row (png_structp png_ptr, + png_bytep old_row, png_bytep new_row) +{ + PNG_CONST int FARDATA png_pass_dsp_mask[7] = + {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; + + if (png_ptr == NULL) + return; + + if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */ + png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]); +} + +void PNGAPI +png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return png_ptr->io_ptr; +} +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h new file mode 100644 index 00000000..8b0621c0 --- /dev/null +++ b/thirdparty/libpng/pngpriv.h @@ -0,0 +1,954 @@ + +/* pngpriv.h - private declarations for use inside libpng + * + * libpng version 1.4.4 - September 23, 2010 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The symbols declared in this file (including the functions declared + * as PNG_EXTERN) are PRIVATE. They are not part of the libpng public + * interface, and are not recommended for use by regular applications. + * Some of them may become public in the future; others may stay private, + * change in an incompatible way, or even disappear. + * Although the libpng users are not forbidden to include this header, + * they should be well aware of the issues that may arise from doing so. + */ + +#ifndef PNGPRIV_H +#define PNGPRIV_H + +#ifndef PNG_VERSION_INFO_ONLY + +#include + +#ifndef PNG_EXTERN +/* The functions exported by PNG_EXTERN are internal functions, which + * aren't usually used outside the library (as far as I know), so it is + * debatable if they should be exported at all. In the future, when it + * is possible to have run-time registry of chunk-handling functions, + * some of these will be made available again. +# define PNG_EXTERN extern + */ +# define PNG_EXTERN +#endif + +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED +# ifdef MACOS + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* Codewarrior on NT has linking problems without this. */ +#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) +# define PNG_ALWAYS_EXTERN +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include +# include +#endif + +#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ + defined(_WIN32) || defined(__WIN32__) +# include /* defines _WINDOWS_ macro */ +#endif + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ +#define PNG_HAVE_IEND 0x10 +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 +#define PNG_HAVE_sRGB 0x80 +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + +/* Flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_QUANTIZE 0x0040 /* formerly PNG_DITHER */ +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 + /* 0x0200 unused */ +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000L +#define PNG_PACKSWAP 0x10000L +#define PNG_SWAP_ALPHA 0x20000L +#define PNG_STRIP_ALPHA 0x40000L +#define PNG_INVERT_ALPHA 0x80000L +#define PNG_USER_TRANSFORM 0x100000L +#define PNG_RGB_TO_GRAY_ERR 0x200000L +#define PNG_RGB_TO_GRAY_WARN 0x400000L +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + /* 0x800000L Unused */ +#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ + +/* Flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_SHIFT 8 +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_SHIFT 3 +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* Flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 +#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 + /* 0x1000 unused */ + /* 0x2000 unused */ + /* 0x4000 unused */ +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L +#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L +#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ +#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000L /* Added to libpng-1.4.0 */ + /* 0x1000000L unused */ + /* 0x2000000L unused */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* Save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ + (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + * ideal-delta..ideal+delta. Each argument is evaluated twice. + * "ideal" and "delta" should be constants, normally simple + * integers, "value" a variable. Added to libpng-1.2.6 JB + */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* Constant strings for known chunk types. If you need to add a chunk, + * define the name here, and add an invocation of the macro wherever it's + * needed. + */ +#define PNG_IHDR PNG_CONST png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} +#define PNG_IDAT PNG_CONST png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} +#define PNG_IEND PNG_CONST png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} +#define PNG_PLTE PNG_CONST png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} +#define PNG_bKGD PNG_CONST png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} +#define PNG_cHRM PNG_CONST png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} +#define PNG_gAMA PNG_CONST png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} +#define PNG_hIST PNG_CONST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} +#define PNG_iCCP PNG_CONST png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} +#define PNG_iTXt PNG_CONST png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} +#define PNG_oFFs PNG_CONST png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} +#define PNG_pCAL PNG_CONST png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} +#define PNG_sCAL PNG_CONST png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} +#define PNG_pHYs PNG_CONST png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} +#define PNG_sBIT PNG_CONST png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} +#define PNG_sPLT PNG_CONST png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} +#define PNG_sRGB PNG_CONST png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} +#define PNG_sTER PNG_CONST png_byte png_sTER[5] = {115, 84, 69, 82, '\0'} +#define PNG_tEXt PNG_CONST png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} +#define PNG_tIME PNG_CONST png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} +#define PNG_tRNS PNG_CONST png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} +#define PNG_zTXt PNG_CONST png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} + + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* These functions are used internally in the code. They generally + * shouldn't be used unless you are writing code to add or replace some + * functionality in libpng. More information about most functions can + * be found in the files where the functions are located. + */ + +/* Allocate memory for an internal libpng struct */ +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); + +/* Free memory from internal libpng struct */ +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); + +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)); +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)); + +/* Free any memory that info_ptr points to and reset struct. */ +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* Function to allocate memory for zlib. PNGAPI is disallowed. */ +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); + +/* Function to free memory for zlib. PNGAPI is disallowed. */ +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); + +/* Next four functions are used internally as callbacks. PNGAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ + +PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif + +PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED +PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); +#endif +#endif + +/* Reset the CRC variable */ +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); + +/* Write the "data" buffer to whatever output you are using */ +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read the chunk header (length + type name) */ +PNG_EXTERN png_uint_32 png_read_chunk_header PNGARG((png_structp png_ptr)); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)); + +/* Decompress data in a chunk that uses compression */ +#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_size_t chunklength, png_size_t prefix_length, + png_size_t *data_length)); +#endif + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +#endif + +/* Write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)); + +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)); + +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); + +#ifdef PNG_WRITE_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, + png_fixed_point file_gamma)); +#endif +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)); +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)); +#endif +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)); +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)); +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)); +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)); +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)); +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)); +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)); +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); +#endif + +#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ +PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type)); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)); +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)); +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); +#endif +#endif +#endif + +/* Called when finished processing a row of data */ +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); + +/* Internal use only. Called before first row of data */ +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr, + png_byte bit_depth)); +#endif + +/* Combine a row of data, dealing with alpha, etc. if requested */ +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Expand an interlaced row */ +/* OLD pre-1.0.9 interface: +PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations)); + */ +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Grab pixels out of a row for an interlaced pass */ +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)); +#endif + +/* Unfilter a row */ +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); + +/* Choose the best filter to use and filter the row data */ +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); + +/* Write out the filtered row. */ +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); +/* Finish a row while reading, dealing with interlacing passes, etc. */ +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); + +/* Initialize the row buffers, etc. */ +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +/* Optional call to update the users info structure */ +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* These are the functions that do the transformations */ +#ifdef PNG_READ_FILLER_SUPPORTED +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +PNG_EXTERN void png_do_quantize PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, png_bytep quantize_lookup)); + +# ifdef PNG_CORRECT_PALETTE_SUPPORTED +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_color, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)); +#else +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_color, png_color_16p background)); +#endif +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* Decode the IHDR chunk */ +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); + +#ifdef PNG_READ_bKGD_SUPPORTED +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED +PNG_EXTERN void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED +PNG_EXTERN void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_sRGB_SUPPORTED +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); + +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)); + +/* Handle the transformations for reading and writing */ +PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); + +PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)); +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +/* Added at libpng version 1.4.0 */ +#ifdef PNG_cHRM_SUPPORTED +PNG_EXTERN int png_check_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_CHECK_cHRM_SUPPORTED +/* Added at libpng version 1.2.34 and 1.4.0 */ +PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2, + unsigned long *hi_product, unsigned long *lo_product)); +#endif +#endif + +/* Added at libpng version 1.4.0 */ +PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type)); + +/* Free all memory used by the read (old method - NOT DLL EXPORTED) */ +PNG_EXTERN void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)); + +/* Free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ +PNG_EXTERN void png_write_destroy PNGARG((png_structp png_ptr)); + +#ifdef USE_FAR_KEYWORD /* memory model conversion function */ +PNG_EXTERN void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + */ +#ifdef PNG_DEBUG +#if (PNG_DEBUG > 0) +#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +#include +#if (PNG_DEBUG > 1) +#ifndef _DEBUG +# define _DEBUG +#endif +#ifndef png_debug +#define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +#endif +#ifndef png_debug1 +#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +#endif +#ifndef png_debug2 +#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +#endif +#endif +#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#ifndef PNG_DEBUG_FILE +#define PNG_DEBUG_FILE stderr +#endif /* PNG_DEBUG_FILE */ + +#if (PNG_DEBUG > 1) +/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on + * non-ISO compilers + */ +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ + } +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ + } +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ + } +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } +# endif +# endif /* __STDC __ */ +#endif /* (PNG_DEBUG > 1) */ + +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +#define png_debug(l, m) +#endif +#ifndef png_debug1 +#define png_debug1(l, m, p1) +#endif +#ifndef png_debug2 +#define png_debug2(l, m, p1, p2) +#endif + +/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +#endif /* PNGPRIV_H */ diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c new file mode 100644 index 00000000..92060d2b --- /dev/null +++ b/thirdparty/libpng/pngread.c @@ -0,0 +1,1361 @@ + +/* pngread.c - read a PNG file + * + * Last changed in libpng 1.4.1 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED +#include "pngpriv.h" + + +/* Create a PNG structure for reading, and allocate any memory needed. */ +png_structp PNGAPI +png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ + +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL)); +} + +/* Alternate create PNG structure for reading, and allocate any memory + * needed. + */ +png_structp PNGAPI +png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + +#ifdef PNG_SETJMP_SUPPORTED + volatile +#endif + png_structp png_ptr; + volatile int png_cleanup_needed = 0; + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + int i; + + png_debug(1, "in png_create_read_struct"); + +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + malloc_fn, mem_ptr); +#else + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); +#endif + if (png_ptr == NULL) + return (NULL); + + /* Added at libpng-1.2.6 */ +#ifdef PNG_USER_LIMITS_SUPPORTED + png_ptr->user_width_max = PNG_USER_WIDTH_MAX; + png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; +# ifdef PNG_USER_CHUNK_CACHE_MAX + /* Added at libpng-1.2.43 and 1.4.0 */ + png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +# endif +# ifdef PNG_SET_USER_CHUNK_MALLOC_MAX + /* Added at libpng-1.2.43 and 1.4.1 */ + png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; +# endif +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* Applications that neglect to set up their own setjmp() and then + encounter a png_error() will longjmp here. Since the jmpbuf is + then meaningless we abort instead of returning. */ +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(png_ptr))) /* Sets longjmp to match setjmp */ +#endif + PNG_ABORT(); +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(png_ptr), jmpbuf, png_sizeof(jmp_buf)); +#endif +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif + + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + if (user_png_ver) + { + i = 0; + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + } + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#ifdef PNG_STDIO_SUPPORTED + char msg[80]; + if (user_png_ver) + { + png_snprintf(msg, 80, + "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + png_snprintf(msg, 80, + "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_warning(png_ptr, + "Incompatible libpng version in application and library"); + + png_cleanup_needed = 1; + } + } + + if (!png_cleanup_needed) + { + /* Initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, + png_ptr->zbuf_size); + if (png_ptr->zbuf == NULL) + png_cleanup_needed = 1; + } + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + if (!png_cleanup_needed) + { + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_warning(png_ptr, "zlib memory error"); + png_cleanup_needed = 1; break; + case Z_VERSION_ERROR: png_warning(png_ptr, "zlib version error"); + png_cleanup_needed = 1; break; + default: png_warning(png_ptr, "Unknown zlib error"); + png_cleanup_needed = 1; + } + } + + if (png_cleanup_needed) + { + /* Clean up PNG structure and deallocate any memory. */ + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, + (png_free_ptr)free_fn, (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + return (NULL); + } + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, NULL, NULL); + + + return (png_ptr); +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* If we haven't checked all of the PNG signature bytes, do so now. */ + if (png_ptr->sig_bytes < 8) + { + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#endif + + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; + } + + for (;;) + { + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#ifdef PNG_READ_bKGD_SUPPORTED + PNG_bKGD; +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + PNG_cHRM; +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + PNG_gAMA; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + PNG_hIST; +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + PNG_iCCP; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + PNG_iTXt; +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + PNG_oFFs; +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + PNG_pCAL; +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + PNG_pHYs; +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + PNG_sBIT; +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + PNG_sCAL; +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + PNG_sPLT; +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + PNG_sRGB; +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + PNG_tEXt; +#endif +#ifdef PNG_READ_tIME_SUPPORTED + PNG_tIME; +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + PNG_tRNS; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + PNG_zTXt; +#endif + png_uint_32 length = png_read_chunk_header(png_ptr); + PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; + + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ + if (!png_memcmp(chunk_name, png_IDAT, 4)) + if (png_ptr->mode & PNG_AFTER_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + if (!png_memcmp(chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, chunk_name)) + { + if (!png_memcmp(chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + else if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + break; + } + } +#endif + else if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); + else if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->idat_size = length; + png_ptr->mode |= PNG_HAVE_IDAT; + break; + } +#ifdef PNG_READ_bKGD_SUPPORTED + else if (!png_memcmp(chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (!png_memcmp(chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + else if (!png_memcmp(chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (!png_memcmp(chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (!png_memcmp(chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (!png_memcmp(chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (!png_memcmp(chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (!png_memcmp(chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (!png_memcmp(chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (!png_memcmp(chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +/* Optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_update_info"); + + if (png_ptr == NULL) + return; + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + else + png_warning(png_ptr, + "Ignoring extra png_read_update_info() call; row buffer not reallocated"); + + png_read_transform_info(png_ptr, info_ptr); +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structp png_ptr) +{ + png_debug(1, "in png_start_read_image"); + + if (png_ptr == NULL) + return; + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void PNGAPI +png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) +{ + PNG_IDAT; + PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, + 0xff}; + PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; + int ret; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_read_row (row %lu, pass %d)", + (unsigned long) png_ptr->row_number, png_ptr->pass); + + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); +#endif +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); +#endif +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + !defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); +#endif +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); +#endif +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); +#endif +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); +#endif +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); +#endif + } + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* If interlaced and we do not need a new row, combine row and return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 1)) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "Invalid attempt to read row data"); + + png_ptr->zstream.next_out = png_ptr->row_buf; + png_ptr->zstream.avail_out = + (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); + do + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, + (png_size_t)png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_benign_error(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression error"); + + } while (png_ptr->zstream.avail_out); + + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + if (png_ptr->row_buf[0]) + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && + (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) + /* Old interface (pre-1.0.9): + * png_do_read_interlace(&(png_ptr->row_info), + * png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + if (row != NULL) + png_combine_row(png_ptr, row, + png_pass_mask[png_ptr->pass]); + } + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, 0xff); + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 0xff); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ + +void PNGAPI +png_read_rows(png_structp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows"); + + if (png_ptr == NULL) + return; + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + else if (rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, NULL); + rp++; + } + else if (dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, NULL, dptr); + dp++; + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ +void PNGAPI +png_read_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i, image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + pass = png_set_interlace_handling(png_ptr); +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled"); + pass = 1; +#endif + + + image_height=png_ptr->height; + png_ptr->num_rows = image_height; /* Make sure this is set correctly */ + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, NULL); + rp++; + } + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_end"); + + if (png_ptr == NULL) + return; + png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ + + do + { + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#ifdef PNG_READ_bKGD_SUPPORTED + PNG_bKGD; +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + PNG_cHRM; +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + PNG_gAMA; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + PNG_hIST; +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + PNG_iCCP; +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + PNG_iTXt; +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + PNG_oFFs; +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + PNG_pCAL; +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + PNG_pHYs; +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + PNG_sBIT; +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + PNG_sCAL; +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + PNG_sPLT; +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + PNG_sRGB; +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + PNG_tEXt; +#endif +#ifdef PNG_READ_tIME_SUPPORTED + PNG_tIME; +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + PNG_tRNS; +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + PNG_zTXt; +#endif + png_uint_32 length = png_read_chunk_header(png_ptr); + PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; + + if (!png_memcmp(chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, chunk_name)) + { + if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_benign_error(png_ptr, "Too many IDATs found"); + } + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + else if (!png_memcmp(chunk_name, png_IDAT, 4)) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. + */ + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_benign_error(png_ptr, "Too many IDATs found"); + png_crc_finish(png_ptr, length); + } + else if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); +#ifdef PNG_READ_bKGD_SUPPORTED + else if (!png_memcmp(chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (!png_memcmp(chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_gAMA_SUPPORTED + else if (!png_memcmp(chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (!png_memcmp(chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (!png_memcmp(chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (!png_memcmp(chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (!png_memcmp(chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (!png_memcmp(chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (!png_memcmp(chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (!png_memcmp(chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (!png_memcmp(chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (!png_memcmp(chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (!png_memcmp(chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } while (!(png_ptr->mode & PNG_HAVE_IEND)); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +/* Free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL, end_info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_read_struct"); + + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + if (png_ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (end_info_ptr_ptr != NULL) + end_info_ptr = *end_info_ptr_ptr; + + png_read_destroy(png_ptr, info_ptr, end_info_ptr); + + if (info_ptr != NULL) + { +#ifdef PNG_TEXT_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } + + if (end_info_ptr != NULL) + { +#ifdef PNG_READ_TEXT_SUPPORTED + png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); +#endif +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)end_info_ptr); +#endif + *end_info_ptr_ptr = NULL; + } + + if (png_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = NULL; + } +} + +/* Free all memory used by the read (old method) */ +void /* PRIVATE */ +png_read_destroy(png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_read_destroy"); + + if (info_ptr != NULL) + png_info_destroy(png_ptr, info_ptr); + + if (end_info_ptr != NULL) + png_info_destroy(png_ptr, end_info_ptr); + + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->chunkdata); +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_free(png_ptr, png_ptr->palette_lookup); + png_free(png_ptr, png_ptr->quantize_index); +#endif +#ifdef PNG_READ_GAMMA_SUPPORTED + png_free(png_ptr, png_ptr->gamma_table); +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED + png_free(png_ptr, png_ptr->gamma_from_1); + png_free(png_ptr, png_ptr->gamma_to_1); +#endif + if (png_ptr->free_me & PNG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->free_me &= ~PNG_FREE_PLTE; +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->free_me & PNG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->free_me &= ~PNG_FREE_TRNS; +#endif +#ifdef PNG_READ_hIST_SUPPORTED + if (png_ptr->free_me & PNG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->free_me &= ~PNG_FREE_HIST; +#endif +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + } +#endif +#endif +#ifdef PNG_TIME_RFC1123_SUPPORTED + png_free(png_ptr, png_ptr->time_buffer); +#endif + + inflateEnd(&png_ptr->zstream); +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +#ifdef PNG_TEXT_SUPPORTED + png_free(png_ptr, png_ptr->current_text); +#endif /* PNG_TEXT_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + + /* Save the important info out of the png_struct, in case it is + * being used again. + */ +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, png_sizeof(png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); +#endif + +} + +void PNGAPI +png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->read_row_fn = read_row_fn; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_read_png(png_structp png_ptr, png_infop info_ptr, + int transforms, + voidp params) +{ + int row; + + if (png_ptr == NULL) + return; + + /* png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error(png_ptr, "Image is too high to process with png_read_png()"); + + /* -------------- image transformations start here ------------------- */ + +#ifdef PNG_READ_16_TO_8_SUPPORTED + /* Tell libpng to strip 16 bit/color files down to 8 bits per color. + */ + if (transforms & PNG_TRANSFORM_STRIP_16) + png_set_strip_16(png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). + */ + if (transforms & PNG_TRANSFORM_STRIP_ALPHA) + png_set_strip_alpha(png_ptr); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). + */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if (transforms & PNG_TRANSFORM_EXPAND) + if ((png_ptr->bit_depth < 8) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || + (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_expand(png_ptr); +#endif + + /* We don't handle background color or gamma transformation or quantizing. + */ + +#ifdef PNG_READ_INVERT_SUPPORTED + /* Invert monochrome files to have 0 as white and 1 as black + */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + /* Flip the RGB pixels to BGR (or RGBA to BGRA) + */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) + */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#ifdef PNG_READ_SWAP_SUPPORTED + /* Swap bytes of 16 bit files to least significant byte first + */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency + */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Expand grayscale image to RGB + */ + if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) + png_set_gray_to_rgb(png_ptr); +#endif + + /* We don't handle adding filler bytes */ + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + if (info_ptr->row_pointers == NULL) + { + png_uint_32 iptr; + + info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, + info_ptr->height * png_sizeof(png_bytep)); + for (iptr=0; iptrheight; iptr++) + info_ptr->row_pointers[iptr] = NULL; + + info_ptr->free_me |= PNG_FREE_ROWS; + + for (row = 0; row < (int)info_ptr->height; row++) + info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr)); + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + transforms = transforms; /* Quiet compiler warnings */ + params = params; + +} +#endif /* PNG_INFO_IMAGE_SUPPORTED */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/thirdparty/libpng/pngrio.c b/thirdparty/libpng/pngrio.c new file mode 100644 index 00000000..59059caf --- /dev/null +++ b/thirdparty/libpng/pngrio.c @@ -0,0 +1,163 @@ + +/* pngrio.c - functions for data input + * + * Last changed in libpng 1.4.1 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED +#include "pngpriv.h" + +/* Read the data from whatever input you are using. The default routine + * reads from a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered reads. This should never be asked + * to read more then 64K on a 16 bit machine. + */ +void /* PRIVATE */ +png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_debug1(4, "reading %d bytes", (int)length); + + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL read function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + if (png_ptr == NULL) + return; + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = fread(data, 1, length, (png_FILE_p)png_ptr->io_ptr); + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#else +/* This is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void PNGAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + png_byte *n_data; + png_FILE_p io_ptr; + + if (png_ptr == NULL) + return; + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { + check = fread(n_data, 1, length, io_ptr); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + err = fread(buf, 1, read, io_ptr); + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if (err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if ((png_uint_32)check != (png_uint_32)length) + png_error(png_ptr, "read Error"); +} +#endif +#endif + +/* This function allows the application to supply a new input function + * for libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png input data structure + * io_ptr - pointer to user supplied structure containing info about + * the input functions. May be NULL. + * read_data_fn - pointer to a new input function that takes as its + * arguments a pointer to a png_struct, a pointer to + * a location where input data can be stored, and a 32-bit + * unsigned int that is the number of bytes to be read. + * To exit and output any fatal error messages the new write + * function should call png_error(png_ptr, "Error msg"). + * May be NULL, in which case libpng's default function will + * be used. + */ +void PNGAPI +png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "It's an error to set both read_data_fn and write_data_fn in the "); + png_warning(png_ptr, + "same structure. Resetting write_data_fn to NULL"); + } + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->output_flush_fn = NULL; +#endif +} +#endif /* PNG_READ_SUPPORTED */ diff --git a/thirdparty/libpng/pngrtran.c b/thirdparty/libpng/pngrtran.c new file mode 100644 index 00000000..b5e8f1a2 --- /dev/null +++ b/thirdparty/libpng/pngrtran.c @@ -0,0 +1,4203 @@ + +/* pngrtran.c - transforms the data in a row for PNG readers + * + * Last changed in libpng 1.4.2 [May 6, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED +#include "pngpriv.h" + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action"); + + if (png_ptr == NULL) + return; + + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + + case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ + png_warning(png_ptr, + "Can't discard critical data on CRC error"); + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + /* Tell libpng how we react to CRC errors in ancillary chunks */ + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* Handle alpha and tRNS via a background color */ +void PNGAPI +png_set_background(png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_debug(1, "in png_set_background"); + + if (png_ptr == NULL) + return; + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_BACKGROUND; + png_memcpy(&(png_ptr->background), background_color, + png_sizeof(png_color_16)); + png_ptr->background_gamma = (float)background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); +} +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +/* Strip 16 bit depth files to 8 bit depth */ +void PNGAPI +png_set_strip_16(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_16"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +void PNGAPI +png_set_strip_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; +} +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Quantize file to 8 bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater then the maximum number, the palette will be + * modified to fit in the maximum number. "full_quantize" indicates + * whether we need a quantizeing cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct FAR * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort FAR * png_dsortp; +typedef png_dsort FAR * FAR * png_dsortpp; + +void PNGAPI +png_set_quantize(png_structp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_uint_16p histogram, + int full_quantize) +{ + png_debug(1, "in png_set_quantize"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_QUANTIZE; + + if (!full_quantize) + { + int i; + + png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + for (i = 0; i < num_palette; i++) + png_ptr->quantize_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + * Perhaps not the best solution, but good enough. + */ + + int i; + + /* Initialize an array to sort colors */ + png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + + /* Initialize the quantize_sort array */ + for (i = 0; i < num_palette; i++) + png_ptr->quantize_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + * bubble sort, and running it until we have sorted + * out enough colors. Note that we don't care about + * sorting all the colors, just finding which are + * least used. + */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* To stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[png_ptr->quantize_sort[j]] + < histogram[png_ptr->quantize_sort[j + 1]]) + { + png_byte t; + + t = png_ptr->quantize_sort[j]; + png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; + png_ptr->quantize_sort[j + 1] = t; + done = 0; + } + } + if (done) + break; + } + + /* Swap the palette around, and set up a table, if necessary */ + if (full_quantize) + { + int j = num_palette; + + /* Put all the useful colors within the max, but don't + * move the others. + */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* Move all the used colors inside the max limit, and + * develop a translation table. + */ + for (i = 0; i < maximum_colors; i++) + { + /* Only move the colors we need to */ + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* Indicate where the color went */ + png_ptr->quantize_index[j] = (png_byte)i; + png_ptr->quantize_index[i] = (png_byte)j; + } + } + + /* Find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->quantize_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* Find the closest color to one we threw out */ + d_index = png_ptr->quantize_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* Point to closest color */ + png_ptr->quantize_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, png_ptr->quantize_sort); + png_ptr->quantize_sort = NULL; + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + * we need to go through a median cut routine, but those + * don't always behave themselves with only a few colors + * as input. So we will just find the closest two colors, + * and throw out one of them (chosen somewhat randomly). + * [We don't understand this at all, so if someone wants to + * work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortp t; + png_dsortpp hash; + + t = NULL; + + /* Initialize palette index arrays */ + png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof(png_byte))); + + /* Initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + png_ptr->index_to_palette[i] = (png_byte)i; + png_ptr->palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * + png_sizeof(png_dsortp))); + + num_new_palette = num_palette; + + /* Initial wild guess at how far apart the farthest pixel + * pair we will be eliminating will be. Larger + * numbers mean more areas will be allocated, Smaller + * numbers run the risk of not saving enough data, and + * having to do this all over again. + * + * I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + + t = (png_dsortp)png_malloc_warn(png_ptr, + (png_uint_32)(png_sizeof(png_dsort))); + if (t == NULL) + break; + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + if (t == NULL) + break; + } + + if (t != NULL) + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)png_ptr->index_to_palette[p->left] + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[png_ptr->index_to_palette[j]] + = palette[num_new_palette]; + if (!full_quantize) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->quantize_index[k] == + png_ptr->index_to_palette[j]) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[next_j]; + if ((int)png_ptr->quantize_index[k] == + num_new_palette) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[j]; + } + } + + png_ptr->index_to_palette[png_ptr->palette_to_index + [num_new_palette]] = png_ptr->index_to_palette[j]; + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] + = png_ptr->palette_to_index[num_new_palette]; + + png_ptr->index_to_palette[j] = + (png_byte)num_new_palette; + png_ptr->palette_to_index[num_new_palette] = + (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, png_ptr->palette_to_index); + png_free(png_ptr, png_ptr->index_to_palette); + png_ptr->palette_to_index = NULL; + png_ptr->index_to_palette = NULL; + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_quantize) + { + int i; + png_bytep distance; + int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + + PNG_QUANTIZE_BLUE_BITS; + int num_red = (1 << PNG_QUANTIZE_RED_BITS); + int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); + int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); + png_size_t num_entries = ((png_size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr, + (png_uint_32)(num_entries * png_sizeof(png_byte))); + + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + png_sizeof(png_byte))); + png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); + int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + + PNG_QUANTIZE_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) +/* Transform the image from the file_gamma to the screen_gamma. We + * only do transformations on images where the file_gamma and screen_gamma + * are not close reciprocals, otherwise it slows things down slightly, and + * also needlessly introduces small errors. + * + * We will turn off gamma transformation later if no semitransparent entries + * are present in the tRNS array for palette images. We can't do it here + * because we don't necessarily have the tRNS chunk yet. + */ +void PNGAPI +png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) +{ + png_debug(1, "in png_set_gamma"); + + if (png_ptr == NULL) + return; + + if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + png_ptr->transformations |= PNG_GAMMA; + png_ptr->gamma = (float)file_gamma; + png_ptr->screen_gamma = (float)scrn_gamma; +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + * + * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified + * to expand only the sample depth but not to expand the tRNS to alpha + * and its name was changed to png_set_expand_gray_1_2_4_to_8(). + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_palette_to_rgb"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} + +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_EXPAND; + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} + + + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_tRNS_to_alpha"); + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +void PNGAPI +png_set_gray_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb"); + + png_ptr->transformations |= PNG_GRAY_TO_RGB; + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, + double green) +{ + int red_fixed = (int)((float)red*100000.0 + 0.5); + int green_fixed = (int)((float)green*100000.0 + 0.5); + if (png_ptr == NULL) + return; + png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); +} +#endif + +void PNGAPI +png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray"); + + if (png_ptr == NULL) + return; + + switch(error_action) + { + case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + + case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + + case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + } + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_ptr->transformations |= PNG_EXPAND; +#else + { + png_warning(png_ptr, + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); + png_ptr->transformations &= ~PNG_RGB_TO_GRAY; + } +#endif + { + png_uint_16 red_int, green_int; + if (red < 0 || green < 0) + { + red_int = 6968; /* .212671 * 32768 + .5 */ + green_int = 23434; /* .715160 * 32768 + .5 */ + } + else if (red + green < 100000L) + { + red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); + green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); + } + else + { + png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); + red_int = 6968; + green_int = 23434; + } + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_blue_coeff = + (png_uint_16)(32768 - red_int - green_int); + } +} +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ +void /* PRIVATE */ +png_init_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_init_read_transformations"); + + { +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_SHIFT_SUPPORTED) || \ + defined(PNG_READ_GAMMA_SUPPORTED) + int color_type = png_ptr->color_type; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Detect gray background and attempt to enable optimization + * for gray --> RGB case + * + * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or + * RGB_ALPHA (in which case need_expand is superfluous anyway), the + * background color might actually be gray yet not be flagged as such. + * This is not a problem for the current code, which uses + * PNG_BACKGROUND_IS_GRAY only to decide when to do the + * png_do_gray_to_rgb() transformation. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + !(color_type & PNG_COLOR_MASK_COLOR)) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + } else if ((png_ptr->transformations & PNG_BACKGROUND) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_GRAY_TO_RGB) && + png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; + } +#endif + + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND)) + { + if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ + { + /* Expand background and tRNS chunks */ + switch (png_ptr->bit_depth) + { + case 1: + png_ptr->background.gray *= (png_uint_16)0xff; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_color.gray *= (png_uint_16)0xff; + png_ptr->trans_color.red = png_ptr->trans_color.green + = png_ptr->trans_color.blue = png_ptr->trans_color.gray; + } + break; + + case 2: + png_ptr->background.gray *= (png_uint_16)0x55; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_color.gray *= (png_uint_16)0x55; + png_ptr->trans_color.red = png_ptr->trans_color.green + = png_ptr->trans_color.blue = png_ptr->trans_color.gray; + } + break; + + case 4: + png_ptr->background.gray *= (png_uint_16)0x11; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_color.gray *= (png_uint_16)0x11; + png_ptr->trans_color.red = png_ptr->trans_color.green + = png_ptr->trans_color.blue = png_ptr->trans_color.gray; + } + break; + + case 8: + + case 16: + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + break; + } + } + else if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { +#ifdef PNG_READ_EXPAND_SUPPORTED + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) +#endif + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop; + istop=(int)png_ptr->num_trans; + for (i=0; itrans_alpha[i] = (png_byte)(255 - png_ptr->trans_alpha[i]); + } + } +#endif + + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + png_ptr->background_1 = png_ptr->background; +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + + if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) + && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0) + < PNG_GAMMA_THRESHOLD)) + { + int i, k; + k=0; + for (i=0; inum_trans; i++) + { + if (png_ptr->trans_alpha[i] != 0 && png_ptr->trans_alpha[i] != 0xff) + k=1; /* Partial transparency is present */ + } + if (k == 0) + png_ptr->transformations &= ~PNG_GAMMA; + } + + if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) && + png_ptr->gamma != 0.0) + { + png_build_gamma_table(png_ptr, png_ptr->bit_depth); + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + /* Could skip if no transparency */ + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + default: + g = 1.0; /* back_1 */ + gs = 1.0; /* back */ + } + + if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + else + { + back.red = (png_byte)(pow( + (double)png_ptr->background.red/255.0, gs) * 255.0 + .5); + back.green = (png_byte)(pow( + (double)png_ptr->background.green/255.0, gs) * 255.0 + + .5); + back.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255.0, gs) * 255.0 + .5); + } + + back_1.red = (png_byte)(pow( + (double)png_ptr->background.red/255.0, g) * 255.0 + .5); + back_1.green = (png_byte)(pow( + (double)png_ptr->background.green/255.0, g) * 255.0 + .5); + back_1.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255.0, g) * 255.0 + .5); + } + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && png_ptr->trans_alpha[i] != 0xff) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans_alpha[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + /* Prevent the transformations being done again, and make sure + * that the now spurious alpha channel is stripped - the code + * has just reduced background composition and gamma correction + * to a simple alpha channel strip. + */ + png_ptr->transformations &= ~PNG_BACKGROUND; + png_ptr->transformations &= ~PNG_GAMMA; + png_ptr->transformations |= PNG_STRIP_ALPHA; + } + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ + else + /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1); + double g = 1.0; + double gs = 1.0; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + } + + png_ptr->background_1.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, g) * m + .5); + png_ptr->background.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, gs) * m + .5); + + if ((png_ptr->background.red != png_ptr->background.green) || + (png_ptr->background.red != png_ptr->background.blue) || + (png_ptr->background.red != png_ptr->background.gray)) + { + /* RGB or RGBA with color background */ + png_ptr->background_1.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, g) * m + .5); + png_ptr->background_1.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, g) * m + .5); + png_ptr->background_1.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, g) * m + .5); + png_ptr->background.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, gs) * m + .5); + png_ptr->background.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, gs) * m + .5); + png_ptr->background.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, gs) * m + .5); + } + else + { + /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ + png_ptr->background_1.red = png_ptr->background_1.green + = png_ptr->background_1.blue = png_ptr->background_1.gray; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + } + } + } + else + /* Transformation does not include PNG_BACKGROUND */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + + /* Done the gamma correction. */ + png_ptr->transformations &= ~PNG_GAMMA; + } + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + else +#endif +#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */ +#ifdef PNG_READ_BACKGROUND_SUPPORTED + /* No GAMMA transformation */ + if ((png_ptr->transformations & PNG_BACKGROUND) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + else if (png_ptr->trans_alpha[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans_alpha[i], back.red); + png_composite(palette[i].green, palette[i].green, + png_ptr->trans_alpha[i], back.green); + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans_alpha[i], back.blue); + } + } + + /* Handled alpha, still need to strip the channel. */ + png_ptr->transformations &= ~PNG_BACKGROUND; + png_ptr->transformations |= PNG_STRIP_ALPHA; + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + png_uint_16 i; + png_uint_16 istop = png_ptr->num_palette; + int sr = 8 - png_ptr->sig_bit.red; + int sg = 8 - png_ptr->sig_bit.green; + int sb = 8 - png_ptr->sig_bit.blue; + + if (sr < 0 || sr > 8) + sr = 0; + if (sg < 0 || sg > 8) + sg = 0; + if (sb < 0 || sb > 8) + sb = 0; + for (i = 0; i < istop; i++) + { + png_ptr->palette[i].red >>= sr; + png_ptr->palette[i].green >>= sg; + png_ptr->palette[i].blue >>= sb; + } + } +#endif /* PNG_READ_SHIFT_SUPPORTED */ + } +#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ + && !defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr) + return; +#endif +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_transform_info"); + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans && + (png_ptr->transformations & PNG_EXPAND_tRNS)) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + else + { + if (png_ptr->num_trans) + { + if (png_ptr->transformations & PNG_EXPAND_tRNS) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + } +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->transformations & PNG_BACKGROUND) + { + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->num_trans = 0; + info_ptr->background = png_ptr->background; + } +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->transformations & PNG_GAMMA) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = png_ptr->gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_ptr->int_gamma; +#endif + } +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) + info_ptr->bit_depth = 8; +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + info_ptr->color_type |= PNG_COLOR_MASK_COLOR; +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if (png_ptr->transformations & PNG_QUANTIZE) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; +#endif + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + +#ifdef PNG_READ_FILLER_SUPPORTED + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + { + info_ptr->channels++; + /* If adding a true alpha channel not just filler */ + if (png_ptr->transformations & PNG_ADD_ALPHA) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (info_ptr->bit_depth < png_ptr->user_transform_depth) + info_ptr->bit_depth = png_ptr->user_transform_depth; + if (info_ptr->channels < png_ptr->user_transform_channels) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + +#ifndef PNG_READ_EXPAND_SUPPORTED + if (png_ptr) + return; +#endif +} + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) + { +#ifdef PNG_STDIO_SUPPORTED + char msg[50]; + + png_snprintf2(msg, 50, + "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number, + png_ptr->pass); + png_error(png_ptr, msg); +#else + png_error(png_ptr, "NULL row buffer"); +#endif + } +#ifdef PNG_WARN_UNINITIALIZED_ROW + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + /* Application has failed to call either png_read_start_image() + * or png_read_update_info() after setting transforms that expand + * pixels. This check added to libpng-1.2.19 + */ +#if (PNG_WARN_UNINITIALIZED_ROW==1) + png_error(png_ptr, "Uninitialized row"); +#else + png_warning(png_ptr, "Uninitialized row"); +#endif +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } + else + { + if (png_ptr->num_trans && + (png_ptr->transformations & PNG_EXPAND_tRNS)) + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_color)); + else + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1); + if (rgb_error) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if ((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0 ) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) + png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_color), &(png_ptr->background) +#ifdef PNG_READ_GAMMA_SUPPORTED + , &(png_ptr->background_1), + png_ptr->gamma_table, png_ptr->gamma_from_1, + png_ptr->gamma_to_1, png_ptr->gamma_16_table, + png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, + png_ptr->gamma_shift +#endif +); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) && +#ifdef PNG_READ_BACKGROUND_SUPPORTED + !((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && +#endif + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->gamma_table, png_ptr->gamma_16_table, + png_ptr->gamma_shift); +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if (png_ptr->transformations & PNG_QUANTIZE) + { + png_do_quantize((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + if (png_ptr->row_info.rowbytes == (png_uint_32)0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if we did not do so above */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth) + png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; + if (png_ptr->user_transform_channels) + png_ptr->row_info.channels = png_ptr->user_transform_channels; +#endif + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + } +#endif + +} + +#ifdef PNG_READ_PACK_SUPPORTED +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +void /* PRIVATE */ +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack"); + + if (row_info->bit_depth < 8) + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +void /* PRIVATE */ +png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits) +{ + png_debug(1, "in png_do_unshift"); + + if ( + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int c; + png_uint_16 value = 0; + png_uint_32 row_width = row_info->width; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift[channels++] = row_info->bit_depth - sig_bits->red; + shift[channels++] = row_info->bit_depth - sig_bits->green; + shift[channels++] = row_info->bit_depth - sig_bits->blue; + } + else + { + shift[channels++] = row_info->bit_depth - sig_bits->gray; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift[channels++] = row_info->bit_depth - sig_bits->alpha; + } + + for (c = 0; c < channels; c++) + { + if (shift[c] <= 0) + shift[c] = 0; + else + value = 1; + } + + if (!value) + return; + + switch (row_info->bit_depth) + { + case 2: + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (bp = row, i = 0; i < istop; i++) + { + *bp >>= 1; + *bp++ &= 0x55; + } + break; + } + + case 4: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | + (png_byte)((int)0xf >> shift[0])); + + for (i = 0; i < istop; i++) + { + *bp >>= shift[0]; + *bp++ &= mask; + } + break; + } + + case 8: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_width * channels; + + for (i = 0; i < istop; i++) + { + *bp++ >>= shift[i%channels]; + } + break; + } + + case 16: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_width; + + for (i = 0; i < istop; i++) + { + value = (png_uint_16)((*bp << 8) + *(bp + 1)); + value >>= shift[i%channels]; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + break; + } + } + } +} +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +/* Chop rows of bit depth 16 down to 8 */ +void /* PRIVATE */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + png_uint_32 istop = row_info->width * row_info->channels; + + for (i = 0; i> 8)) >> 8; + * + * Approximate calculation with shift/add instead of multiply/divide: + * *dp = ((((png_uint_32)(*sp) << 8) | + * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; + * + * What we actually do to avoid extra shifting and conversion: + */ + + *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); +#else + /* Simply discard the low order byte */ + *dp = *sp; +#endif + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_swap_alpha"); + + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + } +} +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_invert_alpha"); + + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } + } + } +} +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED +/* Add filler channel if we have RGB color */ +void /* PRIVATE */ +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_byte hi_filler = (png_byte)((filler>>8) & 0xff); + png_byte lo_filler = (png_byte)(filler & 0xff); + + png_debug(1, "in png_do_read_filler"); + + if ( + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + /* This changes the data from G to GX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + /* This changes the data from G to XG */ + else + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + else if (row_info->bit_depth == 16) + { + /* This changes the data from GG to GGXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from GG to XXGG */ + else + { + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { + /* This changes the data from RGB to RGBX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from RGB to XRGB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + else if (row_info->bit_depth == 16) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + /* This changes the data from RRGGBB to XXRRGGBB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } + } /* COLOR_TYPE == RGB */ +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand grayscale files to RGB, with or without alpha */ +void /* PRIVATE */ +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb"); + + if (row_info->bit_depth >= 8 && + !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels += (png_byte)2; + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ at + * (THIS LINK IS DEAD June 2008) + * New link: + * + * Charles Poynton poynton at poynton.com + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * We approximate this with + * + * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * The calculation is to be done in a linear colorspace. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). + */ +int /* PRIVATE */ +png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) + +{ + png_uint_32 i; + + png_uint_32 row_width = row_info->width; + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if (red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue)>>15]; + } + else + *(dp++) = *(sp - 1); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if (red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + } + else + *(dp++) = *(sp - 1); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if (red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if (red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + } + } + } + } + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if (red != green || red != blue) + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1 + [(rc*red + gc*green + bc*blue)>>15]; + *(dp++) = *(sp++); /* alpha */ + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if (red != green || red != blue) + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = *(sp++); /* alpha */ + } + } + } + else /* RGBA bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if (red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc * red_1 + + gc * green_1 + bc * blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + if (red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + } + } + row_info->channels -= (png_byte)2; + row_info->color_type &= ~PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + return rgb_error; +} +#endif + +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)v; + palette[i].green = (png_byte)v; + palette[i].blue = (png_byte)v; + } +} + + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +void /* PRIVATE */ +png_do_background(png_row_infop row_info, png_bytep row, + png_color_16p trans_color, png_color_16p background +#ifdef PNG_READ_GAMMA_SUPPORTED + , png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift +#endif + ) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + int shift; + + png_debug(1, "in png_do_background"); + + if (background != NULL && + (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || + (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == trans_color->gray) + { + *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 7; + sp++; + } + else + shift--; + } + break; + } + + case 2: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_color->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x03); + png_byte g = (png_byte)((gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03); + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_color->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + break; + } + + case 4: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_color->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x0f); + png_byte g = (png_byte)((gamma_table[p | + (p << 4)] >> 4) & 0x0f); + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_color->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + break; + } + + case 8: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_color->gray) + { + *sp = (png_byte)background->gray; + } + else + { + *sp = gamma_table[*sp]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_color->gray) + { + *sp = (png_byte)background->gray; + } + } + } + break; + } + + case 16: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_color->gray) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_color->gray) + { + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + } + } + break; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_color->red && + *(sp + 1) == trans_color->green && + *(sp + 2) == trans_color->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_color->red && + *(sp + 1) == trans_color->green && + *(sp + 2) == trans_color->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + if (r == trans_color->red && g == trans_color->green && + b == trans_color->blue) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + + if (r == trans_color->red && g == trans_color->green && + b == trans_color->blue) + { + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + } + else if (a == 0) + { + /* Background is already in screen gamma */ + *dp = (png_byte)background->gray; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->gray); + *dp = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_byte a = *(sp + 1); + + if (a == 0xff) + { + *dp = *sp; + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) + { + *dp = (png_byte)background->gray; + } + else + { + png_composite(*dp, *sp, a, background_1->gray); + } +#else + *dp = (png_byte)background->gray; +#endif + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) +#else + else +#endif + { + /* Background is already in screen gamma */ + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, background_1->gray); + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *dp = (png_byte)((w >> 8) & 0xff); + *(dp + 1) = (png_byte)(w & 0xff); + } +#endif + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 2); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) +#else + else +#endif + { + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } +#ifdef PNG_READ_GAMMA_SUPPORTED + else + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, background_1->gray); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } +#endif + } + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + *(dp + 1) = gamma_table[*(sp + 1)]; + *(dp + 2) = gamma_table[*(sp + 2)]; + } + else if (a == 0) + { + /* Background is already in screen gamma */ + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->red); + *dp = gamma_from_1[w]; + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, background_1->green); + *(dp + 1) = gamma_from_1[w]; + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, background_1->blue); + *(dp + 2) = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = *sp; + *(dp + 1) = *(sp + 1); + *(dp + 2) = *(sp + 2); + } + else if (a == 0) + { + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_composite(*dp, *sp, a, background->red); + png_composite(*(dp + 1), *(sp + 1), a, + background->green); + png_composite(*(dp + 2), *(sp + 2), a, + background->blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + else if (a == 0) + { + /* Background is already in screen gamma */ + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v, w, x; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, background_1->red); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *dp = (png_byte)((x >> 8) & 0xff); + *(dp + 1) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, background_1->green); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *(dp + 2) = (png_byte)((x >> 8) & 0xff); + *(dp + 3) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, background_1->blue); + x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; + *(dp + 4) = (png_byte)((x >> 8) & 0xff); + *(dp + 5) = (png_byte)(x & 0xff); + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 6); + } + else if (a == 0) + { + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, background->red); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + png_composite_16(v, g, a, background->green); + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + png_composite_16(v, b, a, background->blue); + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + } + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + row_info->channels--; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + } +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +void /* PRIVATE */ +png_do_gamma(png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift) +{ + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma"); + + if ( + ((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + } + } +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +void /* PRIVATE */ +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_colorp palette, png_bytep trans_alpha, int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette"); + + if ( + row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + + case 2: + { + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift += 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + switch (row_info->bit_depth) + { + case 8: + { + if (trans_alpha != NULL) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + + for (i = 0; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + else + *dp-- = trans_alpha[*sp]; + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + else + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; + + for (i = 0; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + break; + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the already + * expanded transparency value is supplied, an alpha channel is built. + */ +void /* PRIVATE */ +png_do_expand(png_row_infop row_info, png_bytep row, + png_color_16p trans_value) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (png_uint_16)((gray&0x01)*0xff); + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + + case 2: + { + gray = (png_uint_16)((gray&0x03)*0x55); + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + gray = (png_uint_16)((gray&0x0f)*0x11); + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_value != NULL) + { + if (row_info->bit_depth == 8) + { + gray = gray & 0xff; + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*sp == gray) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + } + } + + else if (row_info->bit_depth == 16) + { + png_byte gray_high = (gray >> 8) & 0xff; + png_byte gray_low = gray & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 1) == gray_high && *(sp) == gray_low) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + } + } + + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) + { + if (row_info->bit_depth == 8) + { + png_byte red = trans_value->red & 0xff; + png_byte green = trans_value->green & 0xff; + png_byte blue = trans_value->blue & 0xff; + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + png_byte red_high = (trans_value->red >> 8) & 0xff; + png_byte green_high = (trans_value->green >> 8) & 0xff; + png_byte blue_high = (trans_value->blue >> 8) & 0xff; + png_byte red_low = trans_value->red & 0xff; + png_byte green_low = trans_value->green & 0xff; + png_byte blue_low = trans_value->blue & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 5) == red_high && + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + } +} +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +void /* PRIVATE */ +png_do_quantize(png_row_infop row_info, png_bytep row, + png_bytep palette_lookup, png_bytep quantize_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_quantize"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && + palette_lookup && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* This looks real messy, but the compiler will reduce + * it down to a reasonable formula. For example, with + * 5 bits per color, we get: + * p = (((r >> 3) & 0x1f) << 10) | + * (((g >> 3) & 0x1f) << 5) | + * ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + quantize_lookup && row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + *sp = quantize_lookup[*sp]; + } + } + } +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +static PNG_CONST int png_gamma_shift[] = + {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00}; + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + * + * See the PNG extensions document for an integer algorithm for creating + * the gamma tables. Maybe we will implement that here someday. + * + * We should only reach this point if + * + * the file_gamma is known (i.e., the gAMA or sRGB chunk is present, + * or the application has provided a file_gamma) + * + * AND + * { + * the screen_gamma is known + * + * OR + * + * RGB_to_gray transformation is being performed + * } + * + * AND + * { + * the screen_gamma is different from the reciprocal of the + * file_gamma by more than the specified threshold + * + * OR + * + * a background color has been specified and the file_gamma + * and screen_gamma are not 1.0, within the specified threshold. + * } + */ + +void /* PRIVATE */ +png_build_gamma_table(png_structp png_ptr, png_byte bit_depth) +{ + png_debug(1, "in png_build_gamma_table"); + + if (bit_depth <= 8) + { + int i; + double g; + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + + else + g = 1.0; + + png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + + + png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + if (png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + + else + g = png_ptr->gamma; /* Probably doing rgb_to_gray */ + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } + else + { + double g; + int i, j, shift, num; + int sig_bit; + png_uint_32 ig; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit = (int)png_ptr->sig_bit.red; + + if ((int)png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if ((int)png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + { + sig_bit = (int)png_ptr->sig_bit.gray; + } + + if (sig_bit > 0) + shift = 16 - sig_bit; + + else + shift = 0; + + if (png_ptr->transformations & PNG_16_TO_8) + { + if (shift < (16 - PNG_MAX_GAMMA_8)) + shift = (16 - PNG_MAX_GAMMA_8); + } + + if (shift > 8) + shift = 8; + + if (shift < 0) + shift = 0; + + png_ptr->gamma_shift = (png_byte)shift; + + num = (1 << (8 - shift)); + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + else + g = 1.0; + + png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr, + (png_uint_32)(num * png_sizeof(png_uint_16p))); + + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) + { + double fin, fout; + png_uint_32 last, max; + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + } + + g = 1.0 / g; + last = 0; + for (i = 0; i < 256; i++) + { + fout = ((double)i + 0.5) / 256.0; + fin = pow(fout, g); + max = (png_uint_32)(fin * (double)((png_uint_32)num << 8)); + while (last <= max) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)( + (png_uint_16)i | ((png_uint_16)i << 8)); + last++; + } + } + while (last < ((png_uint_32)num << 8)) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)65535L; + last++; + } + } + else + { + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + + ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); + + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_table[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr, + (png_uint_32)(num * png_sizeof(png_uint_16p ))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_to_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + + if (png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + + else + g = png_ptr->gamma; /* Probably doing rgb_to_gray */ + + png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr, + (png_uint_32)(num * png_sizeof(png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof(png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_from_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } +} +#endif +/* To do: install integer version of png_build_gamma_table here */ +#endif + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff); + *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c new file mode 100644 index 00000000..11e412b7 --- /dev/null +++ b/thirdparty/libpng/pngrutil.c @@ -0,0 +1,3379 @@ + +/* pngrutil.c - utilities to read a PNG file + * + * Last changed in libpng 1.4.4 [August 26, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_READ_SUPPORTED +#include "pngpriv.h" + +# define png_strtod(p,a,b) strtod(a,b) +png_uint_32 PNGAPI +png_get_uint_31(png_structp png_ptr, png_bytep buf) +{ + png_uint_32 i = png_get_uint_32(buf); + if (i > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range"); + return (i); +} +#ifndef PNG_USE_READ_MACROS +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 (PNGAPI +png_get_uint_32)(png_bytep buf) +{ + png_uint_32 i = + ((png_uint_32)(*(buf )) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + ((png_uint_32)(*(buf + 3)) ) ; + + return (i); +} + +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format and there + * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore + * the following code does a two's complement to native conversion. + */ +png_int_32 (PNGAPI +png_get_int_32)(png_bytep buf) +{ + png_uint_32 u = png_get_uint_32(buf); + if ((u & 0x80000000) == 0) /* non-negative */ + return u; + + u = (u ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + return -(png_int_32)u; +} + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 (PNGAPI +png_get_uint_16)(png_bytep buf) +{ + png_uint_16 i = + ((png_uint_32)(*buf) << 8) + + ((png_uint_32)(*(buf + 1))); + + return (i); +} +#endif /* PNG_USE_READ_MACROS */ + +/* Read the chunk header (length + type name). + * Put the type name into png_ptr->chunk_name, and return the length. + */ +png_uint_32 /* PRIVATE */ +png_read_chunk_header(png_structp png_ptr) +{ + png_byte buf[8]; + png_uint_32 length; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being read. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; +#endif + + /* Read the length and the chunk name */ + png_read_data(png_ptr, buf, 8); + length = png_get_uint_31(png_ptr, buf); + + /* Put the chunk name into png_ptr->chunk_name */ + png_memcpy(png_ptr->chunk_name, buf + 4, 4); + + png_debug2(0, "Reading %s chunk, length = %lu", + png_ptr->chunk_name, length); + + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); + + /* Check to see if chunk name is valid */ + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be read. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; +#endif + + return length; +} + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +{ + if (png_ptr == NULL) + return; + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + * are reading a ancillary or critical chunk, and how the program has set + * things up, we may calculate the CRC on the data and print a message. + * Returns '1' if there was a CRC error, '0' otherwise. + */ +int /* PRIVATE */ +png_crc_finish(png_structp png_ptr, png_uint_32 skip) +{ + png_size_t i; + png_size_t istop = png_ptr->zbuf_size; + + for (i = (png_size_t)skip; i > istop; i -= istop) + { + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + } + if (i) + { + png_crc_read(png_ptr, png_ptr->zbuf, i); + } + + if (png_crc_error(png_ptr)) + { + if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || + (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) + { + png_chunk_warning(png_ptr, "CRC error"); + } + else + { + png_chunk_benign_error(png_ptr, "CRC error"); + return (0); + } + return (1); + } + + return (0); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. + */ +int /* PRIVATE */ +png_crc_error(png_structp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being read */ + /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + else + return (0); +} + +#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ + defined(PNG_READ_iCCP_SUPPORTED) +static png_size_t +png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size, + png_bytep output, png_size_t output_size) +{ + png_size_t count = 0; + + png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */ + png_ptr->zstream.avail_in = size; + + while (1) + { + int ret, avail; + + /* Reset the output buffer each time round - we empty it + * after every inflate call. + */ + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = png_ptr->zbuf_size; + + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; + + /* First copy/count any new output - but only if we didn't + * get an error code. + */ + if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) + { + if (output != 0 && output_size > count) + { + int copy = output_size - count; + if (avail < copy) copy = avail; + png_memcpy(output + count, png_ptr->zbuf, copy); + } + count += avail; + } + + if (ret == Z_OK) + continue; + + /* Termination conditions - always reset the zstream, it + * must be left in inflateInit state. + */ + png_ptr->zstream.avail_in = 0; + inflateReset(&png_ptr->zstream); + + if (ret == Z_STREAM_END) + return count; /* NOTE: may be zero. */ + + /* Now handle the error codes - the API always returns 0 + * and the error message is dumped into the uncompressed + * buffer if available. + */ + { + PNG_CONST char *msg; + if (png_ptr->zstream.msg != 0) + msg = png_ptr->zstream.msg; + else + { +#ifdef PNG_STDIO_SUPPORTED + char umsg[52]; + + switch (ret) + { + case Z_BUF_ERROR: + msg = "Buffer error in compressed datastream in %s chunk"; + break; + case Z_DATA_ERROR: + msg = "Data error in compressed datastream in %s chunk"; + break; + default: + msg = "Incomplete compressed datastream in %s chunk"; + break; + } + + png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); + msg = umsg; +#else + msg = "Damaged compressed datastream in chunk other than IDAT"; +#endif + } + + png_warning(png_ptr, msg); + } + + /* 0 means an error - notice that this code simple ignores + * zero length compressed chunks as a result. + */ + return 0; + } +} + +/* + * Decompress trailing data in a chunk. The assumption is that chunkdata + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +void /* PRIVATE */ +png_decompress_chunk(png_structp png_ptr, int comp_type, + png_size_t chunklength, + png_size_t prefix_size, png_size_t *newlength) +{ + /* The caller should guarantee this */ + if (prefix_size > chunklength) + { + /* The recovery is to delete the chunk. */ + png_warning(png_ptr, "invalid chunklength"); + prefix_size = 0; /* To delete everything */ + } + + else if (comp_type == PNG_COMPRESSION_TYPE_BASE) + { + png_size_t expanded_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + 0/*output*/, 0/*output size*/); + + /* Now check the limits on this chunk - if the limit fails the + * compressed data will be removed, the prefix will remain. + */ +#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max && + (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1)) +#else +# ifdef PNG_USER_CHUNK_MALLOC_MAX + if ((PNG_USER_CHUNK_MALLOC_MAX > 0) && + prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) +# endif +#endif + png_warning(png_ptr, "Exceeded size limit while expanding chunk"); + + /* If the size is zero either there was an error and a message + * has already been output (warning) or the size really is zero + * and we have nothing to do - the code will exit through the + * error case below. + */ +#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \ + defined(PNG_USER_CHUNK_MALLOC_MAX) + else +#endif + if (expanded_size > 0) + { + /* Success (maybe) - really uncompress the chunk. */ + png_size_t new_size = 0; + png_charp text = png_malloc_warn(png_ptr, + prefix_size + expanded_size + 1); + + if (text != NULL) + { + png_memcpy(text, png_ptr->chunkdata, prefix_size); + new_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + (png_bytep)(text + prefix_size), expanded_size); + text[prefix_size + expanded_size] = 0; /* just in case */ + + if (new_size == expanded_size) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + *newlength = prefix_size + expanded_size; + return; /* The success return! */ + } + + png_warning(png_ptr, "png_inflate logic error"); + png_free(png_ptr, text); + } + else + png_warning(png_ptr, "Not enough memory to decompress chunk"); + } + } + + else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + { +#ifdef PNG_STDIO_SUPPORTED + char umsg[50]; + + png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", + comp_type); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, "Unknown zTXt compression type"); +#endif + + /* The recovery is to simply drop the data. */ + } + + /* Generic error return - leave the prefix, delete the compressed + * data, reallocate the chunkdata to remove the potentially large + * amount of compressed data. + */ + { + png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); + if (text != NULL) + { + if (prefix_size > 0) + png_memcpy(text, png_ptr->chunkdata, prefix_size); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + + /* This is an extra zero in the 'uncompressed' part. */ + *(png_ptr->chunkdata + prefix_size) = 0x00; + } + /* Ignore a malloc error here - it is safe. */ + } + + *newlength = prefix_size; +} +#endif + +/* Read and check the IDHR chunk */ +void /* PRIVATE */ +png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR"); + + if (png_ptr->mode & PNG_HAVE_IHDR) + png_error(png_ptr, "Out of place IHDR"); + + /* Check the length */ + if (length != 13) + png_error(png_ptr, "Invalid IHDR chunk"); + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + /* Set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + + /* Find number of channels */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* Set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * + png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); + png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); + png_debug1(3, "channels = %d", png_ptr->channels); + png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes); + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); +} + +/* Read and check the palette */ +void /* PRIVATE */ +png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int num, i; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_colorp pal_ptr; +#endif + + png_debug(1, "in png_handle_PLTE"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before PLTE"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid PLTE after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_error(png_ptr, "Duplicate PLTE chunk"); + + png_ptr->mode |= PNG_HAVE_PLTE; + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring PLTE chunk in grayscale PNG"); + png_crc_finish(png_ptr, length); + return; + } +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_warning(png_ptr, "Invalid palette chunk"); + png_crc_finish(png_ptr, length); + return; + } + + else + { + png_error(png_ptr, "Invalid palette chunk"); + } + } + + num = (int)length / 3; + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* Don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually NEED the PLTE chunk (ie for a paletted image), we do + * whatever the normal CRC configuration tells us. However, if we + * have an RGB image, the PLTE can be considered ancillary, so + * we will act as though it is. + */ +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, 0); + } +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + we have two options: an error abort, or a warning and we + ignore the data in this chunk (which should be OK, since + it's considered ancillary for a RGB or RGBA image). */ + if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + { + if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) + { + png_chunk_benign_error(png_ptr, "CRC error"); + } + else + { + png_chunk_warning(png_ptr, "CRC error"); + return; + } + } + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + } +#endif + + png_set_PLTE(png_ptr, info_ptr, palette, num); + +#ifdef PNG_READ_tRNS_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + if (png_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); + png_ptr->num_trans = (png_uint_16)num; + } + if (info_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); + info_ptr->num_trans = (png_uint_16)num; + } + } + } +#endif + +} + +void /* PRIVATE */ +png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) + { + png_error(png_ptr, "No image in file"); + } + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + if (length != 0) + { + png_warning(png_ptr, "Incorrect IEND chunk length"); + } + png_crc_finish(png_ptr, length); + + info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ +} + +#ifdef PNG_READ_gAMA_SUPPORTED +void /* PRIVATE */ +png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_fixed_point igamma; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before gAMA"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid gAMA after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place gAMA chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) +#ifdef PNG_READ_sRGB_SUPPORTED + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate gAMA chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 4) + { + png_warning(png_ptr, "Incorrect gAMA chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 4); + if (png_crc_finish(png_ptr, 0)) + return; + + igamma = (png_fixed_point)png_get_uint_32(buf); + /* Check for zero gamma */ + if (igamma == 0) + { + png_warning(png_ptr, + "Ignoring gAMA chunk with gamma=0"); + return; + } + +#ifdef PNG_READ_sRGB_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifdef PNG_CONSOLE_IO_SUPPORTED + fprintf(stderr, "gamma = (%d/100000)", (int)igamma); +#endif + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float)igamma / (float)100000.0; +# ifdef PNG_READ_GAMMA_SUPPORTED + png_ptr->gamma = file_gamma; +# endif + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, igamma); +#endif +} +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +void /* PRIVATE */ +png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT"); + + buf[0] = buf[1] = buf[2] = buf[3] = 0; + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sBIT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sBIT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + { + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sBIT chunk"); + } + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + { + png_warning(png_ptr, "Duplicate sBIT chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 3; + else + truelen = (png_size_t)png_ptr->channels; + + if (length != truelen || length > 4) + { + png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + else + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); +} +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +void /* PRIVATE */ +png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[32]; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue; + + png_uint_32 uint_x, uint_y; + + png_debug(1, "in png_handle_cHRM"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before cHRM"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid cHRM after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before cHRM"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) +#ifdef PNG_READ_sRGB_SUPPORTED + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate cHRM chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 32) + { + png_warning(png_ptr, "Incorrect cHRM chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 32); + if (png_crc_finish(png_ptr, 0)) + return; + + uint_x = png_get_uint_32(buf); + uint_y = png_get_uint_32(buf + 4); + int_x_white = (png_fixed_point)uint_x; + int_y_white = (png_fixed_point)uint_y; + + uint_x = png_get_uint_32(buf + 8); + uint_y = png_get_uint_32(buf + 12); + int_x_red = (png_fixed_point)uint_x; + int_y_red = (png_fixed_point)uint_y; + + uint_x = png_get_uint_32(buf + 16); + uint_y = png_get_uint_32(buf + 20); + int_x_green = (png_fixed_point)uint_x; + int_y_green = (png_fixed_point)uint_y; + + uint_x = png_get_uint_32(buf + 24); + uint_y = png_get_uint_32(buf + 28); + int_x_blue = (png_fixed_point)uint_x; + int_y_blue = (png_fixed_point)uint_y; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float)int_x_white / (float)100000.0; + white_y = (float)int_y_white / (float)100000.0; + red_x = (float)int_x_red / (float)100000.0; + red_y = (float)int_y_red / (float)100000.0; + green_x = (float)int_x_green / (float)100000.0; + green_y = (float)int_y_green / (float)100000.0; + blue_x = (float)int_x_blue / (float)100000.0; + blue_y = (float)int_y_blue / (float)100000.0; +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) + { + if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) + { + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n", + white_x, white_y, red_x, red_y); + fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n", + green_x, green_y, blue_x, blue_y); +#else + fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", + (long)int_x_white, (long)int_y_white, + (long)int_x_red, (long)int_y_red); + fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n", + (long)int_x_green, (long)int_y_green, + (long)int_x_blue, (long)int_y_blue); +#endif +#endif /* PNG_CONSOLE_IO_SUPPORTED */ + } + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue); +#endif +} +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED +void /* PRIVATE */ +png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + int intent; + png_byte buf[1]; + + png_debug(1, "in png_handle_sRGB"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sRGB"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sRGB after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sRGB chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + { + png_warning(png_ptr, "Duplicate sRGB chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 1) + { + png_warning(png_ptr, "Incorrect sRGB chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 1); + if (png_crc_finish(png_ptr, 0)) + return; + + intent = buf[0]; + /* Check for bad intent */ + if (intent >= PNG_sRGB_INTENT_LAST) + { + png_warning(png_ptr, "Unknown sRGB intent"); + return; + } + +#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) + { + png_fixed_point igamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + igamma=info_ptr->int_gamma; +#else +# ifdef PNG_FLOATING_POINT_SUPPORTED + igamma=(png_fixed_point)(info_ptr->gamma * 100000.); +# endif +#endif + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED + fprintf(stderr, "incorrect gamma=(%d/100000)\n", + (int)png_ptr->int_gamma); +# else +# ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma); +# endif +# endif +#endif + } + } +#endif /* PNG_READ_gAMA_SUPPORTED */ + +#ifdef PNG_READ_cHRM_SUPPORTED +#ifdef PNG_FIXED_POINT_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000)) + { + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); + } +#endif /* PNG_FIXED_POINT_SUPPORTED */ +#endif /* PNG_READ_cHRM_SUPPORTED */ + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_READ_iCCP_SUPPORTED +void /* PRIVATE */ +png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_byte compression_type; + png_bytep pC; + png_charp profile; + png_uint_32 skip = 0; + png_uint_32 profile_size, profile_length; + png_size_t slength, prefix_length, data_length; + + png_debug(1, "in png_handle_iCCP"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iCCP"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid iCCP after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place iCCP chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) + { + png_warning(png_ptr, "Duplicate iCCP chunk"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "iCCP chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (profile = png_ptr->chunkdata; *profile; profile++) + /* Empty loop to find end of name */ ; + + ++profile; + + /* There should be at least one zero (the compression type byte) + * following the separator, and we should be on it + */ + if ( profile >= png_ptr->chunkdata + slength - 1) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Malformed iCCP chunk"); + return; + } + + /* Compression_type should always be zero */ + compression_type = *profile++; + if (compression_type) + { + png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); + compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 + wrote nonzero) */ + } + + prefix_length = profile - png_ptr->chunkdata; + png_decompress_chunk(png_ptr, compression_type, + slength, prefix_length, &data_length); + + profile_length = data_length - prefix_length; + + if ( prefix_length > data_length || profile_length < 4) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Profile size field missing from iCCP chunk"); + return; + } + + /* Check the profile_size recorded in the first 32 bits of the ICC profile */ + pC = (png_bytep)(png_ptr->chunkdata + prefix_length); + profile_size = ((*(pC ))<<24) | + ((*(pC + 1))<<16) | + ((*(pC + 2))<< 8) | + ((*(pC + 3)) ); + + if (profile_size < profile_length) + profile_length = profile_size; + + if (profile_size > profile_length) + { +#ifdef PNG_STDIO_SUPPORTED + char umsg[50]; +#endif + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Ignoring truncated iCCP profile"); +#ifdef PNG_STDIO_SUPPORTED + + png_snprintf(umsg, 50, "declared profile size = %lu", + (unsigned long)profile_size); + png_warning(png_ptr, umsg); + png_snprintf(umsg, 50, "actual profile length = %lu", + (unsigned long)profile_length); + png_warning(png_ptr, umsg); +#endif + return; + } + + png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, + compression_type, png_ptr->chunkdata + prefix_length, profile_length); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +} +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_sPLT_SUPPORTED +void /* PRIVATE */ +png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep entry_start; + png_sPLT_t new_palette; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_sPLT_entryp pp; +#endif + int data_length, entry_size, i; + png_uint_32 skip = 0; + png_size_t slength; + + png_debug(1, "in png_handle_sPLT"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sPLT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sPLT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "sPLT chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; + entry_start++) + /* Empty loop to find end of name */ ; + ++entry_start; + + /* A sample depth should follow the separator, and we should be on it */ + if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "malformed sPLT chunk"); + return; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata)); + + /* Integrity-check the data length */ + if (data_length % entry_size) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "sPLT chunk has bad length"); + return; + } + + new_palette.nentries = (png_int_32) ( data_length / entry_size); + if ((png_uint_32) new_palette.nentries > + (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry))) + { + png_warning(png_ptr, "sPLT chunk too long"); + return; + } + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; + } + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0; i < new_palette.nentries; i++) + { + pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#else + pp = new_palette.entries; + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif + + /* Discard all chunk data except the name and stash that */ + new_palette.name = png_ptr->chunkdata; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, new_palette.entries); +} +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_tRNS_SUPPORTED +void /* PRIVATE */ +png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tRNS"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid tRNS after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_warning(png_ptr, "Duplicate tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[2]; + + if (length != 2) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_color.gray = png_get_uint_16(buf); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, buf, (png_size_t)length); + png_ptr->num_trans = 1; + png_ptr->trans_color.red = png_get_uint_16(buf); + png_ptr->trans_color.green = png_get_uint_16(buf + 2); + png_ptr->trans_color.blue = png_get_uint_16(buf + 4); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* Should be an error, but we can cope with it. */ + png_warning(png_ptr, "Missing PLTE before tRNS"); + } + if (length > (png_uint_32)png_ptr->num_palette || + length > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + if (length == 0) + { + png_warning(png_ptr, "Zero length tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_ptr->num_trans = (png_uint_16)length; + } + else + { + png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_crc_finish(png_ptr, 0)) + { + png_ptr->num_trans = 0; + return; + } + + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_color)); +} +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED +void /* PRIVATE */ +png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[6]; + + png_debug(1, "in png_handle_bKGD"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before bKGD"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid bKGD after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before bKGD"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + { + png_warning(png_ptr, "Duplicate bKGD chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + truelen = 6; + else + truelen = 2; + + if (length != truelen) + { + png_warning(png_ptr, "Incorrect bKGD chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.index = buf[0]; + if (info_ptr && info_ptr->num_palette) + { + if (buf[0] >= info_ptr->num_palette) + { + png_warning(png_ptr, "Incorrect bKGD chunk index value"); + return; + } + png_ptr->background.red = + (png_uint_16)png_ptr->palette[buf[0]].red; + png_ptr->background.green = + (png_uint_16)png_ptr->palette[buf[0]].green; + png_ptr->background.blue = + (png_uint_16)png_ptr->palette[buf[0]].blue; + } + } + else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + { + png_ptr->background.red = + png_ptr->background.green = + png_ptr->background.blue = + png_ptr->background.gray = png_get_uint_16(buf); + } + else + { + png_ptr->background.red = png_get_uint_16(buf); + png_ptr->background.green = png_get_uint_16(buf + 2); + png_ptr->background.blue = png_get_uint_16(buf + 4); + } + + png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); +} +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +void /* PRIVATE */ +png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + unsigned int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before hIST"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid hIST after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before hIST"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) + { + png_warning(png_ptr, "Duplicate hIST chunk"); + png_crc_finish(png_ptr, length); + return; + } + + num = length / 2 ; + if (num != (unsigned int) png_ptr->num_palette || num > + (unsigned int) PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Incorrect hIST chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_hIST(png_ptr, info_ptr, readbuf); +} +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +void /* PRIVATE */ +png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pHYs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pHYs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_warning(png_ptr, "Duplicate pHYs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect pHYs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); +} +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +void /* PRIVATE */ +png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before oFFs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid oFFs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_warning(png_ptr, "Duplicate oFFs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect oFFs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); +} +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +/* Read the pCAL chunk (described in the PNG Extensions document) */ +void /* PRIVATE */ +png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_int_32 X0, X1; + png_byte type, nparams; + png_charp buf, units, endptr; + png_charpp params; + png_size_t slength; + int i; + + png_debug(1, "in png_handle_pCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + { + png_warning(png_ptr, "Duplicate pCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)", + length + 1); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "No memory for pCAL purpose"); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string"); + for (buf = png_ptr->chunkdata; *buf; buf++) + /* Empty loop */ ; + + endptr = png_ptr->chunkdata + slength; + + /* We need to have at least 12 bytes after the purpose string + in order to get the parameter information. */ + if (endptr <= buf + 12) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters"); + /* Check that we have the right number of parameters for known + equation types. */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_warning(png_ptr, "Invalid pCAL parameters for equation type"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + else if (type >= PNG_EQUATION_LAST) + { + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array"); + params = (png_charpp)png_malloc_warn(png_ptr, + (png_size_t)(nparams * png_sizeof(png_charp))); + if (params == NULL) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "No memory for pCAL params"); + return; + } + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < (int)nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d", i); + for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, params); + return; + } + } + + png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, + units, params); + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, params); +} +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +/* Read the sCAL chunk */ +void /* PRIVATE */ +png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp ep; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double width, height; + png_charp vp; +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp swidth, sheight; +#endif +#endif + png_size_t slength; + + png_debug(1, "in png_handle_sCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + { + png_warning(png_ptr, "Duplicate sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)", + length + 1); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + + ep = png_ptr->chunkdata + 1; /* Skip unit byte */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + width = png_strtod(png_ptr, ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed width string in sCAL chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); + if (swidth == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + png_memcpy(swidth, ep, png_strlen(ep)); +#endif +#endif + + for (ep = png_ptr->chunkdata; *ep; ep++) + /* Empty loop */ ; + ep++; + + if (png_ptr->chunkdata + slength < ep) + { + png_warning(png_ptr, "Truncated sCAL chunk"); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); +#endif + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + +#ifdef PNG_FLOATING_POINT_SUPPORTED + height = png_strtod(png_ptr, ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed height string in sCAL chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); + if (sheight == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, swidth); + return; + } + png_memcpy(sheight, ep, png_strlen(ep)); +#endif +#endif + + if (png_ptr->chunkdata + slength < ep +#ifdef PNG_FLOATING_POINT_SUPPORTED + || width <= 0. || height <= 0. +#endif + ) + { + png_warning(png_ptr, "Invalid sCAL data"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif + return; + } + + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight); +#endif +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif +} +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +void /* PRIVATE */ +png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Out of place tIME chunk"); + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + { + png_warning(png_ptr, "Duplicate tIME chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 7) + { + png_warning(png_ptr, "Incorrect tIME chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 7); + if (png_crc_finish(png_ptr, 0)) + return; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); +} +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +/* Note: this does not properly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + png_size_t slength; + int ret; + + png_debug(1, "in png_handle_tEXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for tEXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tEXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "No memory to process text chunk"); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + key = png_ptr->chunkdata; + + key[slength] = 0x00; + + for (text = key; *text; text++) + /* Empty loop to find end of key */ ; + + if (text != key + slength) + text++; + + text_ptr = (png_textp)png_malloc_warn(png_ptr, + png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process text chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = text; + text_ptr->text_length = png_strlen(text); + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, text_ptr); + if (ret) + png_warning(png_ptr, "Insufficient memory to process text chunk"); +} +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp text; + int comp_type; + int ret; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_zTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for zTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before zTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "zTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "Out of memory processing zTXt chunk"); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (text = png_ptr->chunkdata; *text; text++) + /* Empty loop */ ; + + /* zTXt must have some text after the chunkdataword */ + if (text >= png_ptr->chunkdata + slength - 2) + { + png_warning(png_ptr, "Truncated zTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + else + { + comp_type = *(++text); + if (comp_type != PNG_TEXT_COMPRESSION_zTXt) + { + png_warning(png_ptr, "Unknown compression type in zTXt chunk"); + comp_type = PNG_TEXT_COMPRESSION_zTXt; + } + text++; /* Skip the compression_method byte */ + } + prefix_len = text - png_ptr->chunkdata; + + png_decompress_chunk(png_ptr, comp_type, + (png_size_t)length, prefix_len, &data_len); + + text_ptr = (png_textp)png_malloc_warn(png_ptr, + png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process zTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + text_ptr->compression = comp_type; + text_ptr->key = png_ptr->chunkdata; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = png_ptr->chunkdata + prefix_len; + text_ptr->text_length = data_len; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + if (ret) + png_error(png_ptr, "Insufficient memory to store zTXt chunk"); +} +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp key, lang, text, lang_key; + int comp_flag; + int comp_type = 0; + int ret; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_iTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for iTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "iTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "No memory to process iTXt chunk"); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + png_ptr->chunkdata[slength] = 0x00; + + for (lang = png_ptr->chunkdata; *lang; lang++) + /* Empty loop */ ; + lang++; /* Skip NUL separator */ + + /* iTXt must have a language tag (possibly empty), two compression bytes, + * translated keyword (possibly empty), and possibly some text after the + * keyword + */ + + if (lang >= png_ptr->chunkdata + slength - 3) + { + png_warning(png_ptr, "Truncated iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + else + { + comp_flag = *lang++; + comp_type = *lang++; + } + + for (lang_key = lang; *lang_key; lang_key++) + /* Empty loop */ ; + lang_key++; /* Skip NUL separator */ + + if (lang_key >= png_ptr->chunkdata + slength) + { + png_warning(png_ptr, "Truncated iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + for (text = lang_key; *text; text++) + /* Empty loop */ ; + text++; /* Skip NUL separator */ + if (text >= png_ptr->chunkdata + slength) + { + png_warning(png_ptr, "Malformed iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + + prefix_len = text - png_ptr->chunkdata; + + key=png_ptr->chunkdata; + if (comp_flag) + png_decompress_chunk(png_ptr, comp_type, + (size_t)length, prefix_len, &data_len); + else + data_len = png_strlen(png_ptr->chunkdata + prefix_len); + text_ptr = (png_textp)png_malloc_warn(png_ptr, + png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + text_ptr->compression = (int)comp_flag + 1; + text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); + text_ptr->lang = png_ptr->chunkdata + (lang - key); + text_ptr->itxt_length = data_len; + text_ptr->text_length = 0; + text_ptr->key = png_ptr->chunkdata; + text_ptr->text = png_ptr->chunkdata + prefix_len; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + if (ret) + png_error(png_ptr, "Insufficient memory to store iTXt chunk"); +} +#endif + +/* This function is called when we haven't found a handler for a + chunk. If there isn't a problem with the chunk itself (ie bad + chunk name, CRC, or a critical chunk), the chunk is silently ignored + -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which + case it will be saved away to be written out later. */ +void /* PRIVATE */ +png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_unknown"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for unknown chunk"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (png_ptr->mode & PNG_HAVE_IDAT) + { + PNG_IDAT; + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ + png_ptr->mode |= PNG_AFTER_IDAT; + } + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + } + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + || (png_ptr->read_user_chunk_fn != NULL) +#endif + ) + { +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + png_memcpy((png_charp)png_ptr->unknown_chunk.name, + (png_charp)png_ptr->chunk_name, + png_sizeof(png_ptr->unknown_chunk.name)); + png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] + = '\0'; + png_ptr->unknown_chunk.size = (png_size_t)length; + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + else + { + png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); + } +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + if (png_ptr->read_user_chunk_fn != NULL) + { + /* Callback to user unknown chunk handler */ + int ret; + ret = (*(png_ptr->read_user_chunk_fn)) + (png_ptr, &png_ptr->unknown_chunk); + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + if (ret == 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + } + } + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + else +#endif + skip = length; + + png_crc_finish(png_ptr, skip); + +#ifndef PNG_READ_USER_CHUNKS_SUPPORTED + info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ +#endif +} + +/* This function is called to verify that a chunk name is valid. + This function can't have the "critical chunk check" incorporated + into it, since in the future we will need to be able to call user + functions to handle unknown critical chunks after we check that + the chunk name itself is valid. */ + +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) + +void /* PRIVATE */ +png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) +{ + png_debug(1, "in png_check_chunk_name"); + if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || + isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) + { + png_chunk_error(png_ptr, "invalid chunk type"); + } +} + +/* Combines the row recently read in with the existing pixels in the + row. This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined, + a zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. If + you want all pixels to be combined, pass 0xff (255) in mask. */ + +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1, "in png_combine_row"); + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); + } + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_inc, s_start, s_end; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x01; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 2: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x03; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 4: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + default: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + png_byte m = 0x80; + + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + png_memcpy(dp, sp, pixel_bytes); + } + + sp += pixel_bytes; + dp += pixel_bytes; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + } + } +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* OLD pre-1.0.9 interface: +void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations) + */ +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; + png_uint_32 transformations = png_ptr->transformations; + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* Offset to next interlace block */ + PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_read_interlace"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_uint_32 i; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 4: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + int jstop = png_pass_inc[pass]; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0xf); + int j; + + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + default: + { + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); + png_bytep sp = row + (png_size_t)(row_info->width - 1) + * pixel_bytes; + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; + + int jstop = png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; + int j; + + png_memcpy(v, sp, pixel_bytes); + for (j = 0; j < jstop; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sp -= pixel_bytes; + } + break; + } + } + row_info->width = final_width; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); + } +#ifndef PNG_READ_PACKSWAP_SUPPORTED + transformations = transformations; /* Silence compiler warning */ +#endif +} +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, + png_bytep prev_row, int filter) +{ + png_debug(1, "in png_read_filter_row"); + png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter); + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + case PNG_FILTER_VALUE_SUB: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_UP: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_AVG: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *lp++) / 2 ) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_PAETH: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) /* Use leftover rp,pp */ + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + break; + } + default: + png_warning(png_ptr, "Ignoring bad adaptive filter type"); + *row = 0; + break; + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void /* PRIVATE */ +png_read_finish_row(png_structp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + png_debug(1, "in png_read_finish_row"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset(png_ptr->prev_row, 0, + png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (!(png_ptr->num_rows)) + continue; + } + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; + } while (png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + { + PNG_IDAT; + char extra; + int ret; + + png_ptr->zstream.next_out = (Byte *)&extra; + png_ptr->zstream.avail_out = (uInt)1; + for (;;) + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_byte chunk_length[4]; + + png_crc_finish(png_ptr, 0); + + png_read_data(png_ptr, chunk_length, 4); + png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_warning(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression Error"); + + if (!(png_ptr->zstream.avail_out)) + { + png_warning(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + + } + png_ptr->zstream.avail_out = 0; + } + + if (png_ptr->idat_size || png_ptr->zstream.avail_in) + png_warning(png_ptr, "Extra compression data"); + + inflateReset(&png_ptr->zstream); + + png_ptr->mode |= PNG_AFTER_IDAT; +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +void /* PRIVATE */ +png_read_start_row(png_structp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int max_pixel_depth; + png_size_t row_bytes; + + png_debug(1, "in png_read_start_row"); + png_ptr->zstream.avail_in = 0; + png_init_read_transformations(png_ptr); +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + } + else +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + } + max_pixel_depth = png_ptr->pixel_depth; + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + if (png_ptr->num_trans) + max_pixel_depth *= 2; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & (PNG_FILLER)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + max_pixel_depth = 32; + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + else + max_pixel_depth = 32; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + } +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if ( +#ifdef PNG_READ_EXPAND_SUPPORTED + (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || +#endif +#ifdef PNG_READ_FILLER_SUPPORTED + (png_ptr->transformations & (PNG_FILLER)) || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + int user_pixel_depth = png_ptr->user_transform_depth* + png_ptr->user_transform_channels; + if (user_pixel_depth > max_pixel_depth) + max_pixel_depth=user_pixel_depth; + } +#endif + + /* Align the width on the next larger 8 pixels. Mainly used + * for interlacing + */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* Calculate the maximum bytes needed, adding a byte and a pixel + * for safety's sake + */ + row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + + 1 + ((max_pixel_depth + 7) >> 3); +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + + if (row_bytes + 48 > png_ptr->old_big_row_buf_size) + { + png_free(png_ptr, png_ptr->big_row_buf); + if (png_ptr->interlaced) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 48); + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, + row_bytes + 48); + png_ptr->old_big_row_buf_size = row_bytes + 48; + +#ifdef PNG_ALIGNED_MEMORY_SUPPORTED + /* Use 16-byte aligned memory for row_buf with at least 16 bytes + * of padding before and after row_buf. + */ + png_ptr->row_buf = png_ptr->big_row_buf + 32 + - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16); + png_ptr->old_big_row_buf_size = row_bytes + 48; +#else + /* Use 32 bytes of padding before and 16 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 32; +#endif + png_ptr->old_big_row_buf_size = row_bytes + 48; + } + +#ifdef PNG_MAX_MALLOC_64K + if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1)) + png_error(png_ptr, "Row has too many bytes to allocate in memory"); + + if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size) + { + png_free(png_ptr, png_ptr->prev_row); + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( + png_ptr->rowbytes + 1)); + png_ptr->old_prev_row_size = png_ptr->rowbytes + 1; + } + + png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %lu,", png_ptr->width); + png_debug1(3, "height = %lu,", png_ptr->height); + png_debug1(3, "iwidth = %lu,", png_ptr->iwidth); + png_debug1(3, "num_rows = %lu,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} +#endif /* PNG_READ_SUPPORTED */ diff --git a/thirdparty/libpng/pngset.c b/thirdparty/libpng/pngset.c new file mode 100644 index 00000000..1f972c4e --- /dev/null +++ b/thirdparty/libpng/pngset.c @@ -0,0 +1,1167 @@ + +/* pngset.c - storage of image information into info struct + * + * Last changed in libpng 1.4.1 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#include "pngpriv.h" + +#ifdef PNG_bKGD_SUPPORTED +void PNGAPI +png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) +{ + png_debug1(1, "in %s storage function", "bKGD"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_structp png_ptr, png_infop info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_debug1(1, "in %s storage function", "cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_white = (float)white_x; + info_ptr->y_white = (float)white_y; + info_ptr->x_red = (float)red_x; + info_ptr->y_red = (float)red_y; + info_ptr->x_green = (float)green_x; + info_ptr->y_green = (float)green_y; + info_ptr->x_blue = (float)blue_x; + info_ptr->y_blue = (float)blue_y; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5); + info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5); + info_ptr->int_x_red = (png_fixed_point)( red_x*100000.+0.5); + info_ptr->int_y_red = (png_fixed_point)( red_y*100000.+0.5); + info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5); + info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5); + info_ptr->int_x_blue = (png_fixed_point)( blue_x*100000.+0.5); + info_ptr->int_y_blue = (png_fixed_point)( blue_y*100000.+0.5); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif /* PNG_FLOATING_POINT_SUPPORTED */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_debug1(1, "in %s storage function", "cHRM fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_CHECK_cHRM_SUPPORTED + if (png_check_cHRM_fixed(png_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y)) +#endif + { + info_ptr->int_x_white = white_x; + info_ptr->int_y_white = white_y; + info_ptr->int_x_red = red_x; + info_ptr->int_y_red = red_y; + info_ptr->int_x_green = green_x; + info_ptr->int_y_green = green_y; + info_ptr->int_x_blue = blue_x; + info_ptr->int_y_blue = blue_y; +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->x_white = (float)(white_x/100000.); + info_ptr->y_white = (float)(white_y/100000.); + info_ptr->x_red = (float)( red_x/100000.); + info_ptr->y_red = (float)( red_y/100000.); + info_ptr->x_green = (float)(green_x/100000.); + info_ptr->y_green = (float)(green_y/100000.); + info_ptr->x_blue = (float)( blue_x/100000.); + info_ptr->y_blue = (float)( blue_y/100000.); +#endif + info_ptr->valid |= PNG_INFO_cHRM; + } +} +#endif /* PNG_FIXED_POINT_SUPPORTED */ +#endif /* PNG_cHRM_SUPPORTED */ + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +{ + double png_gamma; + + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Check for overflow */ + if (file_gamma > 21474.83) + { + png_warning(png_ptr, "Limiting gamma to 21474.83"); + png_gamma=21474.83; + } + else + png_gamma = file_gamma; + info_ptr->gamma = (float)png_gamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = (int)(png_gamma*100000.+.5); +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if (png_gamma == 0.0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif +void PNGAPI +png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point + int_gamma) +{ + png_fixed_point png_gamma; + + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (int_gamma > (png_fixed_point)PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Limiting gamma to 21474.83"); + png_gamma=PNG_UINT_31_MAX; + } + else + { + if (int_gamma < 0) + { + png_warning(png_ptr, "Setting negative gamma to zero"); + png_gamma = 0; + } + else + png_gamma = int_gamma; + } +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = (float)(png_gamma/100000.); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_gamma; +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if (png_gamma == 0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif + +#ifdef PNG_hIST_SUPPORTED +void PNGAPI +png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function", "hIST"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->num_palette == 0 || info_ptr->num_palette + > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, + "Invalid palette size, hIST allocation skipped"); + return; + } + + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); + /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in + * version 1.2.1 + */ + png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16)); + if (png_ptr->hist == NULL) + { + png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + return; + } + + for (i = 0; i < info_ptr->num_palette; i++) + png_ptr->hist[i] = hist[i]; + info_ptr->hist = png_ptr->hist; + info_ptr->valid |= PNG_INFO_hIST; + + info_ptr->free_me |= PNG_FREE_HIST; +} +#endif + +void PNGAPI +png_set_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + png_debug1(1, "in %s storage function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type = (png_byte)color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + /* Check for potential overflow */ + if (width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + info_ptr->rowbytes = 0; + else + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); +} + +#ifdef PNG_oFFs_SUPPORTED +void PNGAPI +png_set_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "oFFs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +void PNGAPI +png_set_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params) +{ + png_size_t length; + int i; + + png_debug1(1, "in %s storage function", "pCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + length = png_strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)", + (unsigned long)length); + info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_purpose == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL purpose"); + return; + } + png_memcpy(info_ptr->pcal_purpose, purpose, length); + + png_debug(3, "storing X0, X1, type, and nparams in info"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = png_strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)", + (unsigned long)length); + info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_units == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL units"); + return; + } + png_memcpy(info_ptr->pcal_units, units, length); + + info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, + (png_size_t)((nparams + 1) * png_sizeof(png_charp))); + if (info_ptr->pcal_params == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL params"); + return; + } + + png_memset(info_ptr->pcal_params, 0, (nparams + 1) * png_sizeof(png_charp)); + + for (i = 0; i < nparams; i++) + { + length = png_strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, + (unsigned long)length); + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_params[i] == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + return; + } + png_memcpy(info_ptr->pcal_params[i], params[i], length); + } + + info_ptr->valid |= PNG_INFO_pCAL; + info_ptr->free_me |= PNG_FREE_PCAL; +} +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_structp png_ptr, png_infop info_ptr, + int unit, double width, double height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + info_ptr->scal_pixel_width = width; + info_ptr->scal_pixel_height = height; + + info_ptr->valid |= PNG_INFO_sCAL; +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int unit, png_charp swidth, png_charp sheight) +{ + png_size_t length; + + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + + length = png_strlen(swidth) + 1; + png_debug1(3, "allocating unit for info (%u bytes)", + (unsigned int)length); + info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, + "Memory allocation failed while processing sCAL"); + return; + } + png_memcpy(info_ptr->scal_s_width, swidth, length); + + length = png_strlen(sheight) + 1; + png_debug1(3, "allocating unit for info (%u bytes)", + (unsigned int)length); + info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_height == NULL) + { + png_free (png_ptr, info_ptr->scal_s_width); + info_ptr->scal_s_width = NULL; + png_warning(png_ptr, + "Memory allocation failed while processing sCAL"); + return; + } + png_memcpy(info_ptr->scal_s_height, sheight, length); + info_ptr->valid |= PNG_INFO_sCAL; + info_ptr->free_me |= PNG_FREE_SCAL; +} +#endif +#endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +void PNGAPI +png_set_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "pHYs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structp png_ptr, png_infop info_ptr, + png_colorp palette, int num_palette) +{ + + png_debug1(1, "in %s storage function", "PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Invalid palette length"); + else + { + png_warning(png_ptr, "Invalid palette length"); + return; + } + } + + /* It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); + + /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead + * of num_palette entries, in case of an invalid PNG file that has + * too-large sample values. + */ + png_ptr->palette = (png_colorp)png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); + png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + + info_ptr->free_me |= PNG_FREE_PLTE; + + info_ptr->valid |= PNG_INFO_PLTE; +} + +#ifdef PNG_sBIT_SUPPORTED +void PNGAPI +png_set_sBIT(png_structp png_ptr, png_infop info_ptr, + png_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function", "sBIT"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof(png_color_8)); + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#ifdef PNG_sRGB_SUPPORTED +void PNGAPI +png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) +{ + png_debug1(1, "in %s storage function", "sRGB"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->srgb_intent = (png_byte)intent; + info_ptr->valid |= PNG_INFO_sRGB; +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, + int intent) +{ +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_file_gamma; +#endif +#endif +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y; +#endif + png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_set_sRGB(png_ptr, info_ptr, intent); + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float).45455; + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + int_file_gamma = 45455L; + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); +#endif +#endif + +#ifdef PNG_cHRM_SUPPORTED + int_white_x = 31270L; + int_white_y = 32900L; + int_red_x = 64000L; + int_red_y = 33000L; + int_green_x = 30000L; + int_green_y = 60000L; + int_blue_x = 15000L; + int_blue_y = 6000L; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float).3127; + white_y = (float).3290; + red_x = (float).64; + red_y = (float).33; + green_x = (float).30; + green_y = (float).60; + blue_x = (float).15; + blue_y = (float).06; +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y); +#endif +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#endif /* cHRM */ +} +#endif /* sRGB */ + + +#ifdef PNG_iCCP_SUPPORTED +void PNGAPI +png_set_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_charp new_iccp_profile; + png_uint_32 length; + + png_debug1(1, "in %s storage function", "iCCP"); + + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + length = png_strlen(name)+1; + new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length); + if (new_iccp_name == NULL) + { + png_warning(png_ptr, "Insufficient memory to process iCCP chunk"); + return; + } + png_memcpy(new_iccp_name, name, length); + new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen); + if (new_iccp_profile == NULL) + { + png_free (png_ptr, new_iccp_name); + png_warning(png_ptr, + "Insufficient memory to process iCCP profile"); + return; + } + png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + /* Compression is always zero but is here so the API and info structure + * does not have to change if we introduce multiple compression types + */ + info_ptr->iccp_compression = (png_byte)compression_type; + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +void PNGAPI +png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int ret; + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); + if (ret) + png_error(png_ptr, "Insufficient memory to store text"); +} + +int /* PRIVATE */ +png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int i; + + png_debug1(1, "in %s storage function", ((png_ptr == NULL || + png_ptr->chunk_name[0] == '\0') ? + "text" : (png_const_charp)png_ptr->chunk_name)); + + if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + return(0); + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. + */ + if (info_ptr->num_text + num_text > info_ptr->max_text) + { + if (info_ptr->text != NULL) + { + png_textp old_text; + int old_max; + + old_max = info_ptr->max_text; + info_ptr->max_text = info_ptr->num_text + num_text + 8; + old_text = info_ptr->text; + info_ptr->text = (png_textp)png_malloc_warn(png_ptr, + (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); + if (info_ptr->text == NULL) + { + png_free(png_ptr, old_text); + return(1); + } + png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max * + png_sizeof(png_text))); + png_free(png_ptr, old_text); + } + else + { + info_ptr->max_text = num_text + 8; + info_ptr->num_text = 0; + info_ptr->text = (png_textp)png_malloc_warn(png_ptr, + (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); + if (info_ptr->text == NULL) + return(1); + info_ptr->free_me |= PNG_FREE_TEXT; + } + png_debug1(3, "allocated %d entries for info_ptr->text", + info_ptr->max_text); + } + for (i = 0; i < num_text; i++) + { + png_size_t text_length, key_len; + png_size_t lang_len, lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + key_len = png_strlen(text_ptr[i].key); + + if (text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + + else +#ifdef PNG_iTXt_SUPPORTED + { + /* Set iTXt data */ + + if (text_ptr[i].lang != NULL) + lang_len = png_strlen(text_ptr[i].lang); + else + lang_len = 0; + if (text_ptr[i].lang_key != NULL) + lang_key_len = png_strlen(text_ptr[i].lang_key); + else + lang_key_len = 0; + } +#else /* PNG_iTXt_SUPPORTED */ + { + png_warning(png_ptr, "iTXt chunk not supported"); + continue; + } +#endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +#ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + else +#endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + + else + { + text_length = png_strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = (png_charp)png_malloc_warn(png_ptr, + (png_size_t) + (key_len + text_length + lang_len + lang_key_len + 4)); + if (textp->key == NULL) + return(1); + png_debug2(2, "Allocated %lu bytes at %x in png_set_text", + (unsigned long)(png_uint_32) + (key_len + lang_len + lang_key_len + text_length + 4), + (int)textp->key); + + png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len)); + *(textp->key + key_len) = '\0'; +#ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + { + textp->lang = textp->key + key_len + 1; + png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang + lang_len) = '\0'; + textp->lang_key = textp->lang + lang_len + 1; + png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key + lang_key_len) = '\0'; + textp->text = textp->lang_key + lang_key_len + 1; + } + else +#endif + { +#ifdef PNG_iTXt_SUPPORTED + textp->lang=NULL; + textp->lang_key=NULL; +#endif + textp->text = textp->key + key_len + 1; + } + if (text_length) + png_memcpy(textp->text, text_ptr[i].text, + (png_size_t)(text_length)); + *(textp->text + text_length) = '\0'; + +#ifdef PNG_iTXt_SUPPORTED + if (textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + else +#endif + + { + textp->text_length = text_length; +#ifdef PNG_iTXt_SUPPORTED + textp->itxt_length = 0; +#endif + } + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d", info_ptr->num_text); + } + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +void PNGAPI +png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) +{ + png_debug1(1, "in %s storage function", "tIME"); + + if (png_ptr == NULL || info_ptr == NULL || + (png_ptr->mode & PNG_WROTE_tIME)) + return; + + png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof(png_time)); + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +void PNGAPI +png_set_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep trans_alpha, int num_trans, png_color_16p trans_color) +{ + png_debug1(1, "in %s storage function", "tRNS"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (trans_alpha != NULL) + { + /* It may not actually be necessary to set png_ptr->trans_alpha here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); + + /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + png_ptr->trans_alpha = info_ptr->trans_alpha = (png_bytep)png_malloc(png_ptr, + (png_size_t)PNG_MAX_PALETTE_LENGTH); + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + png_memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); + } + + if (trans_color != NULL) + { + int sample_max = (1 << info_ptr->bit_depth); + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + (int)trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + ((int)trans_color->red > sample_max || + (int)trans_color->green > sample_max || + (int)trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + png_memcpy(&(info_ptr->trans_color), trans_color, + png_sizeof(png_color_16)); + if (num_trans == 0) + num_trans = 1; + } + + info_ptr->num_trans = (png_uint_16)num_trans; + if (num_trans != 0) + { + info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->free_me |= PNG_FREE_TRNS; + } +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +void PNGAPI +png_set_sPLT(png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries) +/* + * entries - array of png_sPLT_t structures + * to be added to the list of palettes + * in the info structure. + * nentries - number of palette structures to be + * added. + */ +{ + png_sPLT_tp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL) + return; + + np = (png_sPLT_tp)png_malloc_warn(png_ptr, + (info_ptr->splt_palettes_num + nentries) * + (png_size_t)png_sizeof(png_sPLT_t)); + if (np == NULL) + { + png_warning(png_ptr, "No memory for sPLT palettes"); + return; + } + + png_memcpy(np, info_ptr->splt_palettes, + info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes=NULL; + + for (i = 0; i < nentries; i++) + { + png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; + png_sPLT_tp from = entries + i; + png_uint_32 length; + + length = png_strlen(from->name) + 1; + to->name = (png_charp)png_malloc_warn(png_ptr, (png_size_t)length); + if (to->name == NULL) + { + png_warning(png_ptr, + "Out of memory while processing sPLT chunk"); + continue; + } + png_memcpy(to->name, from->name, length); + to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, + (png_size_t)(from->nentries * png_sizeof(png_sPLT_entry))); + if (to->entries == NULL) + { + png_warning(png_ptr, + "Out of memory while processing sPLT chunk"); + png_free(png_ptr, to->name); + to->name = NULL; + continue; + } + png_memcpy(to->entries, from->entries, + from->nentries * png_sizeof(png_sPLT_entry)); + to->nentries = from->nentries; + to->depth = from->depth; + } + + info_ptr->splt_palettes = np; + info_ptr->splt_palettes_num += nentries; + info_ptr->valid |= PNG_INFO_sPLT; + info_ptr->free_me |= PNG_FREE_SPLT; +} +#endif /* PNG_sPLT_SUPPORTED */ + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +void PNGAPI +png_set_unknown_chunks(png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + return; + + np = (png_unknown_chunkp)png_malloc_warn(png_ptr, + (png_size_t)((info_ptr->unknown_chunks_num + num_unknowns) * + png_sizeof(png_unknown_chunk))); + if (np == NULL) + { + png_warning(png_ptr, + "Out of memory while processing unknown chunk"); + return; + } + + png_memcpy(np, info_ptr->unknown_chunks, + info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk)); + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + + for (i = 0; i < num_unknowns; i++) + { + png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; + png_unknown_chunkp from = unknowns + i; + + png_memcpy((png_charp)to->name, (png_charp)from->name, + png_sizeof(from->name)); + to->name[png_sizeof(to->name)-1] = '\0'; + to->size = from->size; + /* Note our location in the read or write sequence */ + to->location = (png_byte)(png_ptr->mode & 0xff); + + if (from->size == 0) + to->data=NULL; + else + { + to->data = (png_bytep)png_malloc_warn(png_ptr, + (png_size_t)from->size); + if (to->data == NULL) + { + png_warning(png_ptr, + "Out of memory while processing unknown chunk"); + to->size = 0; + } + else + png_memcpy(to->data, from->data, from->size); + } + } + + info_ptr->unknown_chunks = np; + info_ptr->unknown_chunks_num += num_unknowns; + info_ptr->free_me |= PNG_FREE_UNKN; +} +void PNGAPI +png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, + int chunk, int location) +{ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < + (int)info_ptr->unknown_chunks_num) + info_ptr->unknown_chunks[chunk].location = (png_byte)location; +} +#endif + + +#ifdef PNG_MNG_FEATURES_SUPPORTED +png_uint_32 PNGAPI +png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features"); + + if (png_ptr == NULL) + return (png_uint_32)0; + png_ptr->mng_features_permitted = + (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); + return (png_uint_32)png_ptr->mng_features_permitted; +} +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +void PNGAPI +png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep + chunk_list, int num_chunks) +{ + png_bytep new_list, p; + int i, old_num_chunks; + if (png_ptr == NULL) + return; + if (num_chunks == 0) + { + if (keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) + png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS) + png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + return; + } + if (chunk_list == NULL) + return; + old_num_chunks = png_ptr->num_chunk_list; + new_list=(png_bytep)png_malloc(png_ptr, + (png_size_t) + (5*(num_chunks + old_num_chunks))); + if (png_ptr->chunk_list != NULL) + { + png_memcpy(new_list, png_ptr->chunk_list, + (png_size_t)(5*old_num_chunks)); + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + } + png_memcpy(new_list + 5*old_num_chunks, chunk_list, + (png_size_t)(5*num_chunks)); + for (p = new_list + 5*old_num_chunks + 4, i = 0; inum_chunk_list = old_num_chunks + num_chunks; + png_ptr->chunk_list = new_list; + png_ptr->free_me |= PNG_FREE_LIST; +} +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +void PNGAPI +png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +{ + png_debug1(1, "in %s storage function", "rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + info_ptr->row_pointers = row_pointers; + if (row_pointers) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +void PNGAPI +png_set_compression_buffer_size(png_structp png_ptr, + png_size_t size) +{ + if (png_ptr == NULL) + return; + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf_size = size; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; +} + +void PNGAPI +png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +{ + if (png_ptr && info_ptr) + info_ptr->valid &= ~mask; +} + + + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* This function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7ffffffL. + */ + if (png_ptr == NULL) + return; + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} + +/* This function was added to libpng 1.4.0 */ +void PNGAPI +png_set_chunk_cache_max (png_structp png_ptr, + png_uint_32 user_chunk_cache_max) +{ + if (png_ptr) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; +} + +/* This function was added to libpng 1.4.1 */ +void PNGAPI +png_set_chunk_malloc_max (png_structp png_ptr, + png_alloc_size_t user_chunk_malloc_max) +{ + if (png_ptr) + png_ptr->user_chunk_malloc_max = + (png_size_t)user_chunk_malloc_max; +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_set_benign_errors(png_structp png_ptr, int allowed) +{ + png_debug(1, "in png_set_benign_errors"); + + if (allowed) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + else + png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; +} +#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngtest.c b/thirdparty/libpng/pngtest.c new file mode 100644 index 00000000..6317751c --- /dev/null +++ b/thirdparty/libpng/pngtest.c @@ -0,0 +1,1632 @@ + +/* pngtest.c - a simple test program to test libpng + * + * Last changed in libpng 1.4.1 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This program reads in a PNG image, writes it out again, and then + * compares the two files. If the files are identical, this shows that + * the basic chunk handling, filtering, and (de)compression code is working + * properly. It does not currently test all of the transforms, although + * it probably should. + * + * The program will report "FAIL" in certain legitimate cases: + * 1) when the compression level or filter selection method is changed. + * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. + * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks + * exist in the input file. + * 4) others not listed here... + * In these cases, it is best to check with another tool such as "pngcheck" + * to see what the differences between the two files are. + * + * If a filename is given on the command-line, then this file is used + * for the input, rather than the default "pngtest.png". This allows + * testing a wide variety of files easily. You can also test a number + * of files at once by typing "pngtest -m file1.png file2.png ..." + */ + +#include "png.h" +#include "pngpriv.h" + +# include +# include +# define FCLOSE(file) fclose(file) + +#ifndef PNG_STDIO_SUPPORTED + typedef FILE * png_FILE_p; +#endif + +/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ +#endif + +/* Turn on CPU timing +#define PNGTEST_TIMING +*/ + +#ifndef PNG_FLOATING_POINT_SUPPORTED +#undef PNGTEST_TIMING +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#include +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +#define PNG_tIME_STRING_LENGTH 29 +static int tIME_chunk_present = 0; +static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; +#endif + +static int verbose = 0; + +int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); + +#ifdef __TURBOC__ +#include +#endif + +/* Defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* For DOS */ + +/* In case a system header (e.g., on AIX) defined jmpbuf */ +#ifdef jmpbuf +# undef jmpbuf +#endif + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +/* Example of using row callbacks to make a simple progress meter */ +static int status_pass = 1; +static int status_dots_requested = 0; +static int status_dots = 1; + +void +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) + return; + if (status_pass != pass) + { + fprintf(stdout, "\n Pass %d: ", pass); + status_pass = pass; + status_dots = 31; + } + status_dots--; + if (status_dots == 0) + { + fprintf(stdout, "\n "); + status_dots=30; + } + fprintf(stdout, "r"); +} + +void +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) + return; + fprintf(stdout, "w"); +} + + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +/* Example of using user transform callback (we don't transform anything, + * but merely examine the row filters. We set this to 256 rather than + * 5 in case illegal filter values are present.) + */ +static png_uint_32 filters_used[256]; +void +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + if (png_ptr != NULL && row_info != NULL) + ++filters_used[*(data - 1)]; +} +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +/* Example of using user transform callback (we don't transform anything, + * but merely count the zero samples) + */ + +static png_uint_32 zero_samples; + +void +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + png_bytep dp = data; + if (png_ptr == NULL)return; + + /* Contents of row_info: + * png_uint_32 width width of row + * png_uint_32 rowbytes number of bytes in row + * png_byte color_type color type of pixels + * png_byte bit_depth bit depth of samples + * png_byte channels number of channels (1-4) + * png_byte pixel_depth bits per pixel (depth*channels) + */ + + /* Counts the number of zero samples (or zero pixels if color_type is 3 */ + + if (row_info->color_type == 0 || row_info->color_type == 3) + { + int pos = 0; + png_uint_32 n, nstop; + for (n = 0, nstop=row_info->width; nbit_depth == 1) + { + if (((*dp << pos++ ) & 0x80) == 0) + zero_samples++; + if (pos == 8) + { + pos = 0; + dp++; + } + } + if (row_info->bit_depth == 2) + { + if (((*dp << (pos+=2)) & 0xc0) == 0) + zero_samples++; + if (pos == 8) + { + pos = 0; + dp++; + } + } + if (row_info->bit_depth == 4) + { + if (((*dp << (pos+=4)) & 0xf0) == 0) + zero_samples++; + if (pos == 8) + { + pos = 0; + dp++; + } + } + if (row_info->bit_depth == 8) + if (*dp++ == 0) + zero_samples++; + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + dp+=2; + } + } + } + else /* Other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if (row_info->color_type > 3)color_channels--; + + for (n = 0, nstop=row_info->width; nbit_depth == 8) + if (*dp++ == 0) + zero_samples++; + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + dp+=2; + } + } + if (row_info->color_type > 3) + { + dp++; + if (row_info->bit_depth == 16) + dp++; + } + } + } +} +#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ + +static int wrote_question = 0; + +#ifndef PNG_STDIO_SUPPORTED +/* START of code to validate stdio-free compilation */ +/* These copies of the default read/write functions come from pngrio.c and + * pngwio.c. They allow "don't include stdio" testing of the library. + * This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ + +#ifndef USE_FAR_KEYWORD +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check = 0; + png_voidp io_ptr; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + io_ptr = png_get_io_ptr(png_ptr); + if (io_ptr != NULL) + { + check = fread(data, 1, length, (png_FILE_p)io_ptr); + } + + if (check != length) + { + png_error(png_ptr, "Read Error!"); + } +} +#else +/* This is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr)); + if ((png_bytep)n_data == data) + { + check = fread(n_data, 1, length, io_ptr); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + err = fread(buf, 1, 1, io_ptr); + png_memcpy(data, buf, read); /* Copy far buffer to near buffer */ + if (err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "read Error"); +} +#endif /* USE_FAR_KEYWORD */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +static void +pngtest_flush(png_structp png_ptr) +{ + /* Do nothing; fflush() is said to be just a waste of energy. */ + png_ptr = png_ptr; /* Stifle compiler warning */ +} +#endif + +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +#ifndef USE_FAR_KEYWORD +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + png_FILE_p io_ptr; + io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr)); + + check = fwrite(data, 1, length, io_ptr); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#else +/* This is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { + check = fwrite(near_data, 1, length, io_ptr); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ + err = fwrite(buf, 1, written, io_ptr); + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#endif /* USE_FAR_KEYWORD */ + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void +pngtest_warning(png_structp png_ptr, png_const_charp message) +{ + PNG_CONST char *name = "UNKNOWN (ERROR!)"; + char *test; + test = png_get_error_ptr(png_ptr); + if (test == NULL) + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); + else + fprintf(STDERR, "%s: libpng warning: %s\n", test, message); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void +pngtest_error(png_structp png_ptr, png_const_charp message) +{ + pngtest_warning(png_ptr, message); + /* We can return because png_error calls the default handler, which is + * actually OK in this case. + */ +} +#endif /* !PNG_STDIO_SUPPORTED */ +/* END of code to validate stdio-free compilation */ + +/* START of code to validate memory allocation and deallocation */ +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * This piece of code can be compiled to validate max 64K allocations + * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. + */ +typedef struct memory_information +{ + png_alloc_size_t size; + png_voidp pointer; + struct memory_information FAR *next; +} memory_information; +typedef memory_information FAR *memory_infop; + +static memory_infop pinformation = NULL; +static int current_allocation = 0; +static int maximum_allocation = 0; +static int total_allocation = 0; +static int num_allocations = 0; + +png_voidp png_debug_malloc + PNGARG((png_structp png_ptr, png_alloc_size_t size)); +void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); + +png_voidp +png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) +{ + + /* png_malloc has already tested for NULL; png_create_struct calls + * png_debug_malloc directly, with png_ptr == NULL which is OK + */ + + if (size == 0) + return (NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + /* Disable malloc_fn and free_fn */ + memory_infop pinfo; + png_set_mem_fn(png_ptr, NULL, NULL, NULL); + pinfo = (memory_infop)png_malloc(png_ptr, + png_sizeof(*pinfo)); + pinfo->size = size; + current_allocation += size; + total_allocation += size; + num_allocations ++; + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + pinfo->pointer = png_malloc(png_ptr, size); + /* Restore malloc_fn and free_fn */ + png_set_mem_fn(png_ptr, + NULL, png_debug_malloc, png_debug_free); + if (size != 0 && pinfo->pointer == NULL) + { + current_allocation -= size; + total_allocation -= size; + png_error(png_ptr, + "out of memory in pngtest->png_debug_malloc"); + } + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + png_memset(pinfo->pointer, 0xdd, pinfo->size); + if (verbose) + printf("png_malloc %lu bytes at %x\n", (unsigned long)size, + pinfo->pointer); + return (png_voidp)(pinfo->pointer); + } +} + +/* Free a pointer. It is removed from the list at the same time. */ +void +png_debug_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + if (ptr == 0) + { +#if 0 /* This happens all the time. */ + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); +#endif + return; + } + + /* Unlink the element from the list. */ + { + memory_infop FAR *ppinfo = &pinformation; + for (;;) + { + memory_infop pinfo = *ppinfo; + if (pinfo->pointer == ptr) + { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + png_memset(ptr, 0x55, pinfo->size); + png_free_default(png_ptr, pinfo); + pinfo = NULL; + break; + } + if (pinfo->next == NULL) + { + fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); + break; + } + ppinfo = &pinfo->next; + } + } + + /* Finally free the data. */ + if (verbose) + printf("Freeing %x\n", ptr); + png_free_default(png_ptr, ptr); + ptr = NULL; +} +#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ +/* END of code to test memory allocation/deallocation */ + + +/* Demonstration of user chunk support of the sTER and vpAg chunks */ +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + +/* (sTER is a public chunk not yet known by libpng. vpAg is a private +chunk used in ImageMagick to store "virtual page" size). */ + +static png_uint_32 user_chunk_data[4]; + + /* 0: sTER mode + 1 + * 1: vpAg width + * 2: vpAg height + * 3: vpAg units + */ + +static int read_user_chunk_callback(png_struct *png_ptr, + png_unknown_chunkp chunk) +{ + png_uint_32 + *my_user_chunk_data; + + /* Return one of the following: + * return (-n); chunk had an error + * return (0); did not recognize + * return (n); success + * + * The unknown chunk structure contains the chunk data: + * png_byte name[5]; + * png_byte *data; + * png_size_t size; + * + * Note that libpng has already taken care of the CRC handling. + */ + + if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ + chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ + { + /* Found sTER chunk */ + if (chunk->size != 1) + return (-1); /* Error return */ + if (chunk->data[0] != 0 && chunk->data[0] != 1) + return (-1); /* Invalid mode */ + my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); + my_user_chunk_data[0]=chunk->data[0]+1; + return (1); + } + + if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ + chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ + return (0); /* Did not recognize */ + + /* Found ImageMagick vpAg chunk */ + + if (chunk->size != 9) + return (-1); /* Error return */ + + my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); + + my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); + my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); + my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; + + return (1); + +} +#endif +/* END of code to demonstrate user chunk support */ + +/* Test one file */ +int +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) +{ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + png_structp read_ptr; + png_infop read_info_ptr, end_info_ptr; +#ifdef PNG_WRITE_SUPPORTED + png_structp write_ptr; + png_infop write_info_ptr; + png_infop write_end_info_ptr; +#else + png_structp write_ptr = NULL; + png_infop write_info_ptr = NULL; + png_infop write_end_info_ptr = NULL; +#endif + png_bytep row_buf; + png_uint_32 y; + png_uint_32 width, height; + int num_pass, pass; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + char inbuf[256], outbuf[256]; + + row_buf = NULL; + + if ((fpin = fopen(inname, "rb")) == NULL) + { + fprintf(STDERR, "Could not find input file %s\n", inname); + return (1); + } + + if ((fpout = fopen(outname, "wb")) == NULL) + { + fprintf(STDERR, "Could not open output file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + png_debug(0, "Allocating read and write structures"); +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + read_ptr = + png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL, NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + read_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +#endif +#ifndef PNG_STDIO_SUPPORTED + png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + user_chunk_data[0] = 0; + user_chunk_data[1] = 0; + user_chunk_data[2] = 0; + user_chunk_data[3] = 0; + png_set_read_user_chunk_fn(read_ptr, user_chunk_data, + read_user_chunk_callback); + +#endif +#ifdef PNG_WRITE_SUPPORTED +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + write_ptr = + png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL, NULL, png_debug_malloc, png_debug_free); +#else + write_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +#endif +#ifndef PNG_STDIO_SUPPORTED + png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#endif + png_debug(0, "Allocating read_info, write_info and end_info structures"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); +#ifdef PNG_WRITE_SUPPORTED + write_info_ptr = png_create_info_struct(write_ptr); + write_end_info_ptr = png_create_info_struct(write_ptr); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_debug(0, "Setting jmpbuf for read struct"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(read_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); + png_free(read_ptr, row_buf); + row_buf = NULL; + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf)); +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Setting jmpbuf for write struct"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(write_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf)); +#endif +#endif +#endif + + png_debug(0, "Initializing input and output streams"); +#ifdef PNG_STDIO_SUPPORTED + png_init_io(read_ptr, fpin); +# ifdef PNG_WRITE_SUPPORTED + png_init_io(write_ptr, fpout); +# endif +#else + png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); +# ifdef PNG_WRITE_SUPPORTED + png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, +# ifdef PNG_WRITE_FLUSH_SUPPORTED + pngtest_flush); +# else + NULL); +# endif +# endif +#endif + if (status_dots_requested == 1) + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, write_row_callback); +#endif + png_set_read_status_fn(read_ptr, read_row_callback); + } + else + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, NULL); +#endif + png_set_read_status_fn(read_ptr, NULL); + } + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + { + int i; + for (i = 0; i<256; i++) + filters_used[i] = 0; + png_set_read_user_transform_fn(read_ptr, count_filters); + } +#endif +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + zero_samples = 0; + png_set_write_user_transform_fn(write_ptr, count_zero_samples); +#endif + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +# endif + png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, + NULL, 0); +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +# endif + png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, + NULL, 0); +#endif + + png_debug(0, "Reading info struct"); + png_read_info(read_ptr, read_info_ptr); + + png_debug(0, "Transferring info struct"); + { + int interlace_type, compression_type, filter_type; + + if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, &compression_type, &filter_type)) + { + png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + color_type, interlace_type, compression_type, filter_type); +#else + color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#endif + } + } +#ifdef PNG_FIXED_POINT_SUPPORTED +#ifdef PNG_cHRM_SUPPORTED + { + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, + &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#ifdef PNG_gAMA_SUPPORTED + { + png_fixed_point gamma; + + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) + png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); + } +#endif +#else /* Use floating point versions */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +#ifdef PNG_cHRM_SUPPORTED + { + double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#ifdef PNG_gAMA_SUPPORTED + { + double gamma; + + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) + png_set_gAMA(write_ptr, write_info_ptr, gamma); + } +#endif +#endif /* Floating point */ +#endif /* Fixed point */ +#ifdef PNG_iCCP_SUPPORTED + { + png_charp name; + png_charp profile; + png_uint_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen)) + { + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif +#ifdef PNG_sRGB_SUPPORTED + { + int intent; + + if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) + png_set_sRGB(write_ptr, write_info_ptr, intent); + } +#endif + { + png_colorp palette; + int num_palette; + + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); + } +#ifdef PNG_bKGD_SUPPORTED + { + png_color_16p background; + + if (png_get_bKGD(read_ptr, read_info_ptr, &background)) + { + png_set_bKGD(write_ptr, write_info_ptr, background); + } + } +#endif +#ifdef PNG_hIST_SUPPORTED + { + png_uint_16p hist; + + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) + png_set_hIST(write_ptr, write_info_ptr, hist); + } +#endif +#ifdef PNG_oFFs_SUPPORTED + { + png_int_32 offset_x, offset_y; + int unit_type; + + if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, + &unit_type)) + { + png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } + } +#endif +#ifdef PNG_pCAL_SUPPORTED + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; + + if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, + &nparams, &units, ¶ms)) + { + png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, + nparams, units, params); + } + } +#endif +#ifdef PNG_pHYs_SUPPORTED + { + png_uint_32 res_x, res_y; + int unit_type; + + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); + } +#endif +#ifdef PNG_sBIT_SUPPORTED + { + png_color_8p sig_bit; + + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) + png_set_sBIT(write_ptr, write_info_ptr, sig_bit); + } +#endif +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED + { + int unit; + double scal_width, scal_height; + + if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + { + int unit; + png_charp scal_width, scal_height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, + scal_height); + } + } +#endif +#endif +#endif +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); + png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); + } + } +#endif +#ifdef PNG_tIME_SUPPORTED + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_info_ptr, mod_time); +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* We have to use png_memcpy instead of "=" because the string + * pointed to by png_convert_to_rfc1123() gets free'ed before + * we use it. + */ + png_memcpy(tIME_string, + png_convert_to_rfc1123(read_ptr, mod_time), + png_sizeof(tIME_string)); + tIME_string[png_sizeof(tIME_string) - 1] = '\0'; + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#ifdef PNG_tRNS_SUPPORTED + { + png_bytep trans_alpha; + int num_trans; + png_color_16p trans_color; + + if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans, + &trans_color)) + { + int sample_max = (1 << bit_depth); + /* libpng doesn't reject a tRNS chunk with out-of-range samples */ + if (!((color_type == PNG_COLOR_TYPE_GRAY && + (int)trans_color->gray > sample_max) || + (color_type == PNG_COLOR_TYPE_RGB && + ((int)trans_color->red > sample_max || + (int)trans_color->green > sample_max || + (int)trans_color->blue > sample_max)))) + png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans, + trans_color); + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); + /* Copy the locations from the read_info_ptr. The automatically + * generated locations in write_info_ptr are wrong because we + * haven't written anything yet. + */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, + unknowns[i].location); + } + } +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Writing info struct"); + +/* If we wanted, we could write info in two steps: + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + */ + png_write_info(write_ptr, write_info_ptr); + +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + if (user_chunk_data[0] != 0) + { + png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; + + unsigned char + ster_chunk_data[1]; + + if (verbose) + fprintf(STDERR, "\n stereo mode = %lu\n", + (unsigned long)(user_chunk_data[0] - 1)); + ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1); + png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1); + } + if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0) + { + png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; + + unsigned char + vpag_chunk_data[9]; + + if (verbose) + fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n", + (unsigned long)user_chunk_data[1], + (unsigned long)user_chunk_data[2], + (unsigned long)user_chunk_data[3]); + png_save_uint_32(vpag_chunk_data, user_chunk_data[1]); + png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]); + vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff); + png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); + } + +#endif +#endif + +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(0, "Allocating row buffer..."); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug1(0, "0x%08lx", (unsigned long)row_buf); +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(0, "Writing row data"); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) + num_pass = png_set_interlace_handling(read_ptr); +# ifdef PNG_WRITE_SUPPORTED + png_set_interlace_handling(write_ptr); +# endif +#else + num_pass = 1; +#endif + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; +#endif + for (pass = 0; pass < num_pass; pass++) + { + png_debug1(0, "Writing row data for pass %d", pass); + for (y = 0; y < height; y++) + { +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, + png_get_rowbytes(read_ptr, read_info_ptr)); +#endif /* !SINGLE_ROWBUF_ALLOC */ + png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1); + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_decode += (t_stop - t_start); + t_start = t_stop; +#endif + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_encode += (t_stop - t_start); + t_start = t_stop; +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); + png_free(read_ptr, row_buf); + row_buf = NULL; +#endif /* !SINGLE_ROWBUF_ALLOC */ + } + } + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); +#endif + + png_debug(0, "Reading and writing end_info data"); + + png_read_end(read_ptr, end_info_ptr); +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); + png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); + } + } +#endif +#ifdef PNG_tIME_SUPPORTED + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_end_info_ptr, mod_time); +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* We have to use png_memcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_memcpy(tIME_string, + png_convert_to_rfc1123(read_ptr, mod_time), + png_sizeof(tIME_string)); + tIME_string[png_sizeof(tIME_string) - 1] = '\0'; + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + { + png_unknown_chunkp unknowns; + int num_unknowns; + num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, + num_unknowns); + /* Copy the locations from the read_info_ptr. The automatically + * generated locations in write_end_info_ptr are wrong because we + * haven't written the end_info yet. + */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, + unknowns[i].location); + } + } +#endif +#ifdef PNG_WRITE_SUPPORTED + png_write_end(write_ptr, write_end_info_ptr); +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED + if (verbose) + { + png_uint_32 iwidth, iheight; + iwidth = png_get_image_width(write_ptr, write_info_ptr); + iheight = png_get_image_height(write_ptr, write_info_ptr); + fprintf(STDERR, "\n Image width = %lu, height = %lu\n", + (unsigned long)iwidth, (unsigned long)iheight); + } +#endif + + png_debug(0, "Destroying data structs"); +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(1, "destroying row_buf for read_ptr"); + png_free(read_ptr, row_buf); + row_buf = NULL; +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_debug(1, "destroying write_end_info_ptr"); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_debug(1, "destroying write_ptr, write_info_ptr"); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + png_debug(0, "Destruction complete."); + + FCLOSE(fpin); + FCLOSE(fpout); + + png_debug(0, "Opening files for comparison"); + if ((fpin = fopen(inname, "rb")) == NULL) + { + fprintf(STDERR, "Could not find file %s\n", inname); + return (1); + } + + if ((fpout = fopen(outname, "rb")) == NULL) + { + fprintf(STDERR, "Could not find file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + for (;;) + { + png_size_t num_in, num_out; + + num_in = fread(inbuf, 1, 1, fpin); + num_out = fread(outbuf, 1, 1, fpout); + + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); + if (wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + + if (!num_in) + break; + + if (png_memcmp(inbuf, outbuf, num_in)) + { + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); + if (wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + } + + FCLOSE(fpin); + FCLOSE(fpout); + + return (0); +} + +/* Input and output filenames */ +#ifdef RISCOS +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; +#else +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; +#endif + +int +main(int argc, char *argv[]) +{ + int multiple = 0; + int ierror = 0; + + fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); + fprintf(STDERR, "%s", png_get_copyright(NULL)); + /* Show the version of libpng used in building the library */ + fprintf(STDERR, " library (%lu):%s", + (unsigned long)png_access_version_number(), + png_get_header_version(NULL)); + /* Show the version of libpng used in building the application */ + fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, + PNG_HEADER_VERSION_STRING); + fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n", + (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); + + /* Do some consistency checking on the memory allocation settings, I'm + * not sure this matters, but it is nice to know, the first of these + * tests should be impossible because of the way the macros are set + * in pngconf.h + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); +#endif + /* I think the following can happen. */ +#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); +#endif + + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) + { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + ++ierror; + } + + if (argc > 1) + { + if (strcmp(argv[1], "-m") == 0) + { + multiple = 1; + status_dots_requested = 0; + } + else if (strcmp(argv[1], "-mv") == 0 || + strcmp(argv[1], "-vm") == 0 ) + { + multiple = 1; + verbose = 1; + status_dots_requested = 1; + } + else if (strcmp(argv[1], "-v") == 0) + { + verbose = 1; + status_dots_requested = 1; + inname = argv[2]; + } + else + { + inname = argv[1]; + status_dots_requested = 0; + } + } + + if (!multiple && argc == 3 + verbose) + outname = argv[2 + verbose]; + + if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) + { + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); + } + + if (multiple) + { + int i; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + for (i=2; isize, + (unsigned int) pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + else + { + int i; + for (i = 0; i<3; ++i) + { + int kerror; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + if (i == 1) status_dots_requested = 1; + else if (verbose == 0)status_dots_requested = 0; + if (i == 0 || verbose == 1 || ierror != 0) + fprintf(STDERR, "\n Testing %s:", inname); + kerror = test_one_file(inname, outname); + if (kerror == 0) + { + if (verbose == 1 || i == 2) + { +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + int k; +#endif +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + fprintf(STDERR, "\n PASS (%lu zero samples)\n", + (unsigned long)zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + for (k = 0; k<256; k++) + if (filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k, (unsigned long)filters_used[k]); +#endif +#ifdef PNG_TIME_RFC1123_SUPPORTED + if (tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n", tIME_string); +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } + else + { + if (verbose == 0 && i != 2) + fprintf(STDERR, "\n Testing %s:", inname); + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation - allocation_now); + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) + { + fprintf(STDERR, " %lu bytes at %x\n", + (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; + fprintf(STDERR, " CPU time used = %.3f seconds", + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " (decoding %.3f,\n", + t_decode/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " encoding %.3f ,", + t_encode/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " other %.3f seconds)\n\n", + t_misc/(float)CLOCKS_PER_SEC); +#endif + + if (ierror == 0) + fprintf(STDERR, " libpng passes test\n"); + else + fprintf(STDERR, " libpng FAILS test\n"); + return (int)(ierror != 0); +} + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_4_4 your_png_h_is_not_version_1_4_4; diff --git a/thirdparty/libpng/pngtrans.c b/thirdparty/libpng/pngtrans.c new file mode 100644 index 00000000..741daf45 --- /dev/null +++ b/thirdparty/libpng/pngtrans.c @@ -0,0 +1,677 @@ + +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * Last changed in libpng 1.4.2 [April 29, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +#include "pngpriv.h" + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structp png_ptr) +{ + png_debug(1, "in png_set_bgr"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Turn on 16 bit byte swapping */ +void PNGAPI +png_set_swap(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap"); + + if (png_ptr == NULL) + return; + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Turn on pixel packing */ +void PNGAPI +png_set_packing(png_structp png_ptr) +{ + png_debug(1, "in png_set_packing"); + + if (png_ptr == NULL) + return; + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; + png_ptr->usr_bit_depth = 8; + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structp png_ptr) +{ + png_debug(1, "in png_set_packswap"); + + if (png_ptr == NULL) + return; + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structp png_ptr, png_color_8p true_bits) +{ + png_debug(1, "in png_set_shift"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structp png_ptr) +{ + png_debug(1, "in png_set_interlace handling"); + + if (png_ptr && png_ptr->interlaced) + { + png_ptr->transformations |= PNG_INTERLACE; + return (7); + } + + return (1); +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_FILLER; + png_ptr->filler = (png_uint_16)filler; + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; + + /* This should probably go in the "do_read_filler" routine. + * I attempted to do that in libpng-1.0.1a but that caused problems + * so I restored it in libpng-1.0.2a + */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_ptr->usr_channels = 4; + } + + /* Also I added this in libpng-1.0.2a (what happens when we expand + * a less-than-8-bit grayscale to GA? */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + } +} + +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha"); + + if (png_ptr == NULL) + return; + png_set_filler(png_ptr, filler, filler_loc); + png_ptr->transformations |= PNG_ADD_ALPHA; +} + +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_mono"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* Invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert"); + + /* This test removed from libpng version 1.0.13 and 1.2.0: + * if (row_info->bit_depth == 1 && + */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 8) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i+=2) + { + *rp = (png_byte)(~(*rp)); + rp+=2; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i+=4) + { + *rp = (png_byte)(~(*rp)); + *(rp+1) = (png_byte)(~(*(rp+1))); + rp+=4; + } + } +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swaps byte order on 16 bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap"); + + if ( + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; + } + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static PNG_CONST png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static PNG_CONST png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static PNG_CONST png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* Swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap"); + + if ( + row_info->bit_depth < 8) + { + png_bytep rp, end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = (png_bytep)onebppswaptable; + else if (row_info->bit_depth == 2) + table = (png_bytep)twobppswaptable; + else if (row_info->bit_depth == 4) + table = (png_bytep)fourbppswaptable; + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* Remove filler or alpha byte(s) */ +void /* PRIVATE */ +png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) +{ + png_debug(1, "in png_do_strip_filler"); + + { + png_bytep sp=row; + png_bytep dp=row; + png_uint_32 row_width=row_info->width; + png_uint_32 i; + + if ((row_info->color_type == PNG_COLOR_TYPE_RGB || + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + /* This converts from RGBX or RGBA to RGB */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + dp+=3; sp+=4; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp++; + } + } + /* This converts from XRGB or ARGB to RGB */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */ + sp += 8; dp += 6; + for (i = 1; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */ + for (i = 0; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + sp+=2; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 48; + row_info->rowbytes = row_width * 6; + } + row_info->channels = 3; + } + else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY || + (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + /* This converts from GX or GA to G */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + for (i = 0; i < row_width; i++) + { + *dp++ = *sp++; + sp++; + } + } + /* This converts from XG or AG to G */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from GGXX or GGAA to GG */ + sp += 4; dp += 2; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXGG or AAGG to GG */ + for (i = 0; i < row_width; i++) + { + sp += 2; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + row_info->channels = 1; + } + if (flags & PNG_FLAG_STRIP_ALPHA) + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + } +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } + } +} +#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_user_transform_info(png_structp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info"); + + if (png_ptr == NULL) + return; +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +#else + if (user_transform_ptr || user_transform_depth || user_transform_channels) + png_warning(png_ptr, + "This version of libpng does not support user transform info"); +#endif +} + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +png_voidp PNGAPI +png_get_user_transform_ptr(png_structp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + return ((png_voidp)png_ptr->user_transform_ptr); +#else + return (NULL); +#endif +} +#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || + PNG_WRITE_USER_TRANSFORM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngwio.c b/thirdparty/libpng/pngwio.c new file mode 100644 index 00000000..513a71a0 --- /dev/null +++ b/thirdparty/libpng/pngwio.c @@ -0,0 +1,241 @@ + +/* pngwio.c - functions for data output + * + * Last changed in libpng 1.4.0 [January 3, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED +#include "pngpriv.h" + +/* Write the data to whatever output you are using. The default routine + * writes to a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered writes. This should never be asked + * to write more than 64K on a 16 bit machine. + */ + +void /* PRIVATE */ +png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL write function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + + if (png_ptr == NULL) + return; + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); + if (check != length) + png_error(png_ptr, "Write Error"); +} +#else +/* This is the model-independent version. Since the standard I/O library + * can't handle far buffers in the medium and small models, we have to copy + * the data. + */ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + if (png_ptr == NULL) + return; + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { + check = fwrite(near_data, 1, length, io_ptr); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ + err = fwrite(buf, 1, written, io_ptr); + if (err != written) + break; + + else + check += err; + + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "Write Error"); +} + +#endif +#endif + +/* This function is called to output any data pending writing (normally + * to disk). After png_flush is called, there should be no data pending + * writing in any buffers. + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void /* PRIVATE */ +png_flush(png_structp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +#ifdef PNG_STDIO_SUPPORTED +void PNGAPI +png_default_flush(png_structp png_ptr) +{ + png_FILE_p io_ptr; + if (png_ptr == NULL) + return; + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + fflush(io_ptr); +} +#endif +#endif + +/* This function allows the application to supply new output functions for + * libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png output data structure + * io_ptr - pointer to user supplied structure containing info about + * the output functions. May be NULL. + * write_data_fn - pointer to a new output function that takes as its + * arguments a pointer to a png_struct, a pointer to + * data to be written, and a 32-bit unsigned int that is + * the number of bytes to be written. The new write + * function should call png_error(png_ptr, "Error msg") + * to exit and output any fatal error messages. May be + * NULL, in which case libpng's default function will + * be used. + * flush_data_fn - pointer to a new flush function that takes as its + * arguments a pointer to a png_struct. After a call to + * the flush function, there should be no data in any buffers + * or pending transmission. If the output method doesn't do + * any buffering of output, a function prototype must still be + * supplied although it doesn't have to do anything. If + * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + * time, output_flush_fn will be ignored, although it must be + * supplied for compatibility. May be NULL, in which case + * libpng's default function will be used, if + * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not + * a good idea if io_ptr does not point to a standard + * *FILE structure. + */ +void PNGAPI +png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + + else + png_ptr->output_flush_fn = png_default_flush; +#else + png_ptr->output_flush_fn = output_flush_fn; +#endif +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + png_warning(png_ptr, + "Attempted to set both read_data_fn and write_data_fn in"); + png_warning(png_ptr, + "the same structure. Resetting read_data_fn to NULL"); + } +} + +#ifdef USE_FAR_KEYWORD +#ifdef _MSC_VER +void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + FP_OFF(near_ptr) = FP_OFF(ptr); + far_ptr = (void FAR *)near_ptr; + + if (check != 0) + if (FP_SEG(ptr) != FP_SEG(far_ptr)) + png_error(png_ptr, "segment lost in conversion"); + + return(near_ptr); +} +# else +void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + near_ptr = (void FAR *)ptr; + far_ptr = (void FAR *)near_ptr; + + if (check != 0) + if (far_ptr != ptr) + png_error(png_ptr, "segment lost in conversion"); + + return(near_ptr); +} +# endif +# endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c new file mode 100644 index 00000000..02520519 --- /dev/null +++ b/thirdparty/libpng/pngwrite.c @@ -0,0 +1,1457 @@ + +/* pngwrite.c - general routines to write a PNG file + * + * Last changed in libpng 1.4.0 [January 3, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Get internal access to png.h */ +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED +#include "pngpriv.h" + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + { + /* Write PNG signature */ + png_write_sig(png_ptr); +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ + (png_ptr->mng_features_permitted)) + { + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + png_ptr->mng_features_permitted = 0; + } +#endif + /* Write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + info_ptr->interlace_type); +#else + 0); +#endif + /* The rest of these check to see if the valid field has the appropriate + * flag set, and if it does, writes the chunk. + */ +#ifdef PNG_WRITE_gAMA_SUPPORTED + if (info_ptr->valid & PNG_INFO_gAMA) + { +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_gAMA(png_ptr, info_ptr->gamma); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); +# endif +#endif + } +#endif +#ifdef PNG_WRITE_sRGB_SUPPORTED + if (info_ptr->valid & PNG_INFO_sRGB) + png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); +#endif +#ifdef PNG_WRITE_iCCP_SUPPORTED + if (info_ptr->valid & PNG_INFO_iCCP) + png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, + info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); +#endif +#ifdef PNG_WRITE_sBIT_SUPPORTED + if (info_ptr->valid & PNG_INFO_sBIT) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif +#ifdef PNG_WRITE_cHRM_SUPPORTED + if (info_ptr->valid & PNG_INFO_cHRM) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_cHRM(png_ptr, + info_ptr->x_white, info_ptr->y_white, + info_ptr->x_red, info_ptr->y_red, + info_ptr->x_green, info_ptr->y_green, + info_ptr->x_blue, info_ptr->y_blue); +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + png_write_cHRM_fixed(png_ptr, + info_ptr->int_x_white, info_ptr->int_y_white, + info_ptr->int_x_red, info_ptr->int_y_red, + info_ptr->int_x_green, info_ptr->int_y_green, + info_ptr->int_x_blue, info_ptr->int_y_blue); +# endif +#endif + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep = png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && !(up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structp png_ptr, png_infop info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if (info_ptr->valid & PNG_INFO_PLTE) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images"); + +#ifdef PNG_WRITE_tRNS_SUPPORTED + if (info_ptr->valid & PNG_INFO_tRNS) + { +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j; + for (j = 0; j<(int)info_ptr->num_trans; j++) + info_ptr->trans_alpha[j] = (png_byte)(255 - info_ptr->trans_alpha[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#ifdef PNG_WRITE_bKGD_SUPPORTED + if (info_ptr->valid & PNG_INFO_bKGD) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif +#ifdef PNG_WRITE_hIST_SUPPORTED + if (info_ptr->valid & PNG_INFO_hIST) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif +#ifdef PNG_WRITE_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED + if (info_ptr->valid & PNG_INFO_pCAL) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif + +#ifdef PNG_sCAL_SUPPORTED + if (info_ptr->valid & PNG_INFO_sCAL) +#ifdef PNG_WRITE_sCAL_SUPPORTED +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) + png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); +#else /* !FLOATING_POINT */ +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#endif /* FIXED_POINT */ +#endif /* FLOATING_POINT */ +#else /* !WRITE_sCAL */ + png_warning(png_ptr, + "png_write_sCAL not supported; sCAL chunk not written"); +#endif /* WRITE_sCAL */ +#endif /* sCAL */ + +#ifdef PNG_WRITE_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif /* pHYs */ + +#ifdef PNG_WRITE_tIME_SUPPORTED + if (info_ptr->valid & PNG_INFO_tIME) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif /* tIME */ + +#ifdef PNG_WRITE_sPLT_SUPPORTED + if (info_ptr->valid & PNG_INFO_sPLT) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif /* sPLT */ + +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + /* Can't get here */ + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif /* tEXt */ + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep = png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_end"); + + if (png_ptr == NULL) + return; + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "No IDATs written into file"); + + /* See if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#ifdef PNG_WRITE_TEXT_SUPPORTED + int i; /* local index variable */ +#endif +#ifdef PNG_WRITE_tIME_SUPPORTED + /* Check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) && + !(png_ptr->mode & PNG_WROTE_tIME)) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); +#endif +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep = png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_AFTER_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* Write end of PNG file */ + png_write_IEND(png_ptr); + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, + * and restored again in libpng-1.2.30, may cause some applications that + * do not set png_ptr->output_flush_fn to crash. If your application + * experiences a problem, please try building libpng with + * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to + * png-mng-implement at lists.sf.net . + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + png_flush(png_ptr); +# endif +#endif +} + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* "tm" structure is not supported on WindowsCE */ +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm"); + + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t"); + + tbuf = gmtime(&ttime); + png_convert_from_struct_tm(ptime, tbuf); +} +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL)); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + volatile int png_cleanup_needed = 0; +#ifdef PNG_SETJMP_SUPPORTED + volatile +#endif + png_structp png_ptr; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + int i; + + png_debug(1, "in png_create_write_struct"); + +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); +#else + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); +#endif /* PNG_USER_MEM_SUPPORTED */ + if (png_ptr == NULL) + return (NULL); + + /* Added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max = PNG_USER_WIDTH_MAX; + png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* Applications that neglect to set up their own setjmp() and then + encounter a png_error() will longjmp here. Since the jmpbuf is + then meaningless we abort instead of returning. */ +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */ +#endif +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(png_ptr), jmpbuf, png_sizeof(jmp_buf)); +#endif + PNG_ABORT(); +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + if (user_png_ver) + { + i = 0; + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + } + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#ifdef PNG_STDIO_SUPPORTED + char msg[80]; + if (user_png_ver) + { + png_snprintf(msg, 80, + "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + png_snprintf(msg, 80, + "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + png_warning(png_ptr, + "Incompatible libpng version in application and library"); + png_cleanup_needed = 1; + } + } + + /* Initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + if (!png_cleanup_needed) + { + png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, + png_ptr->zbuf_size); + if (png_ptr->zbuf == NULL) + png_cleanup_needed = 1; + } + if (png_cleanup_needed) + { + /* Clean up PNG structure and deallocate any memory. */ + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, + (png_free_ptr)free_fn, (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + return (NULL); + } + + png_set_write_fn(png_ptr, NULL, NULL, NULL); + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, NULL, NULL); +#endif + + return (png_ptr); +} + + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows"); + + if (png_ptr == NULL) + return; + + /* Loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + if (png_ptr == NULL) + return; + + png_debug(1, "in png_write_image"); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Initialize interlace handling. If image is not interlaced, + * this will set pass to 1 + */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* Loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* Loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +/* Called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structp png_ptr, png_bytep row) +{ + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_write_row (row %ld, pass %d)", + png_ptr->row_number, png_ptr->pass); + + /* Initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Make sure we wrote the header info */ + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + png_error(png_ptr, + "png_write_info was never called before png_write_row"); + + /* Check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, + "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); +#endif + + png_write_start_row(png_ptr); + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced and not interested in row, return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 0x01)) + { + png_write_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + /* Set up row info for transformations */ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->usr_width; + png_ptr->row_info.channels = png_ptr->usr_channels; + png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); + png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width); + png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE)) + { + png_do_write_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass); + /* This should always get caught above, but still ... */ + if (!(png_ptr->row_info.width)) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + + /* Handle other transformations */ + if (png_ptr->transformations) + png_do_write_transformations(png_ptr); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &(png_ptr->row_info)); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush"); + + if (png_ptr == NULL) + return; + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* Flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structp png_ptr) +{ + int wrote_IDAT; + + png_debug(1, "in png_write_flush"); + + if (png_ptr == NULL) + return; + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + do + { + int ret; + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); + wrote_IDAT = 0; + + /* Check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + if (!(png_ptr->zstream.avail_out)) + { + /* Write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + wrote_IDAT = 1; + } + } while(wrote_IDAT == 1); + + /* If there is any data left to be output, write it into a new IDAT */ + if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) + { + /* Write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + +/* Free all memory used by the write */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_write_struct"); + + if (png_ptr_ptr != NULL) + { + png_ptr = *png_ptr_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + } + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL) + { + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; + } +#endif + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + if (png_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->num_chunk_list = 0; + } +#endif + } + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } + + if (png_ptr != NULL) + { + png_write_destroy(png_ptr); +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = NULL; + } +} + + +/* Free any memory used in png_ptr struct (old method) */ +void /* PRIVATE */ +png_write_destroy(png_structp png_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* Save jump buffer */ +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_write_destroy"); + + /* Free any memory zlib uses */ + deflateEnd(&png_ptr->zstream); + + /* Free our memory. png_free checks NULL for us. */ + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->row_buf); +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->sub_row); + png_free(png_ptr, png_ptr->up_row); + png_free(png_ptr, png_ptr->avg_row); + png_free(png_ptr, png_ptr->paeth_row); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + png_free(png_ptr, png_ptr->time_buffer); +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_filters); + png_free(png_ptr, png_ptr->filter_weights); + png_free(png_ptr, png_ptr->inv_filter_weights); + png_free(png_ptr, png_ptr->filter_costs); + png_free(png_ptr, png_ptr->inv_filter_costs); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Reset structure */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, png_sizeof(png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); +#endif +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter"); + + if (png_ptr == NULL) + return; +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + case 5: + case 6: + case 7: png_warning(png_ptr, "Unknown row filter for method 0"); +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + case PNG_FILTER_VALUE_NONE: + png_ptr->do_filter = PNG_FILTER_NONE; break; +#ifdef PNG_WRITE_FILTER_SUPPORTED + case PNG_FILTER_VALUE_SUB: + png_ptr->do_filter = PNG_FILTER_SUB; break; + case PNG_FILTER_VALUE_UP: + png_ptr->do_filter = PNG_FILTER_UP; break; + case PNG_FILTER_VALUE_AVG: + png_ptr->do_filter = PNG_FILTER_AVG; break; + case PNG_FILTER_VALUE_PAETH: + png_ptr->do_filter = PNG_FILTER_PAETH; break; + default: png_ptr->do_filter = (png_byte)filters; break; +#else + default: png_warning(png_ptr, "Unknown row filter for method 0"); +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + } + + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then add and + * remove them after the start of compression. + */ + if (png_ptr->row_buf != NULL) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Up filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_UP; + } + else + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Average filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_AVG; + } + else + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + png_ptr->paeth_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); + } + else + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + png_ptr->do_filter = PNG_FILTER_NONE; + } + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +/* This allows us to influence the way in which libpng chooses the "best" + * filter for the current scanline. While the "minimum-sum-of-absolute- + * differences metric is relatively fast and effective, there is some + * question as to whether it can be improved upon by trying to keep the + * filtered data going to zlib more consistent, hopefully resulting in + * better compression. + */ +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ +void PNGAPI +png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, + int num_weights, png_doublep filter_weights, + png_doublep filter_costs) +{ + int i; + + png_debug(1, "in png_set_filter_heuristics"); + + if (png_ptr == NULL) + return; + if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return; + } + + if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) + { + heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + } + + if (num_weights < 0 || filter_weights == NULL || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + { + num_weights = 0; + } + + png_ptr->num_prev_filters = (png_byte)num_weights; + png_ptr->heuristic_method = (png_byte)heuristic_method; + + if (num_weights > 0) + { + if (png_ptr->prev_filters == NULL) + { + png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_byte) * num_weights)); + + /* To make sure that the weighting starts out fairly */ + for (i = 0; i < num_weights; i++) + { + png_ptr->prev_filters[i] = 255; + } + } + + if (png_ptr->filter_weights == NULL) + { + png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + + png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + for (i = 0; i < num_weights; i++) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + } + + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] < 0.0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + else + { + png_ptr->inv_filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); + png_ptr->filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); + } + } + } + + /* If, in the future, there are other filter methods, this would + * need to be based on png_ptr->filter. + */ + if (png_ptr->filter_costs == NULL) + { + png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + if (filter_costs == NULL || filter_costs[i] < 0.0) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + else if (filter_costs[i] >= 1.0) + { + png_ptr->inv_filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); + png_ptr->filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); + } + } +} +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +void PNGAPI +png_set_compression_level(png_structp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy"); + + if (png_ptr == NULL) + return; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +void PNGAPI +png_set_compression_window_bits(png_structp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + if (window_bits > 15) + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + else if (window_bits < 8) + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); +#ifndef WBITS_8_OK + /* Avoid libpng bug with 256-byte windows */ + if (window_bits == 8) + { + png_warning(png_ptr, "Compression window is being reset to 512"); + window_bits = 9; + } +#endif + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method"); + + if (png_ptr == NULL) + return; + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; + png_ptr->zlib_method = method; +} + +void PNGAPI +png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->write_row_fn = write_row_fn; +} + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +void PNGAPI +png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn"); + + if (png_ptr == NULL) + return; + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_write_png(png_structp png_ptr, png_infop info_ptr, + int transforms, voidp params) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + +#ifdef PNG_WRITE_INVERT_SUPPORTED + /* Invert monochrome pixels */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + /* Pack pixels into bytes */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + /* Swap location of alpha bytes from ARGB to RGBA */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ + if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + /* Flip BGR pixels to RGB */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED + /* Swap bytes of 16-bit files to most significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* Write the bits */ + if (info_ptr->valid & PNG_INFO_IDAT) + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + transforms = transforms; /* Quiet compiler warnings */ + params = params; +} +#endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngwtran.c b/thirdparty/libpng/pngwtran.c new file mode 100644 index 00000000..070caa54 --- /dev/null +++ b/thirdparty/libpng/pngwtran.c @@ -0,0 +1,566 @@ + +/* pngwtran.c - transforms the data in a row for PNG writers + * + * Last changed in libpng 1.4.1 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED +#include "pngpriv.h" + +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif +#ifdef PNG_WRITE_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->flags); +#endif +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif +#ifdef PNG_WRITE_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#ifdef PNG_WRITE_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +} + +#ifdef PNG_WRITE_PACK_SUPPORTED +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +void /* PRIVATE */ +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack"); + + if (row_info->bit_depth == 8 && + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + sp++; + if (mask > 1) + mask >>= 1; + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + if (mask != 0x80) + *dp = (png_byte)v; + break; + } + case 2: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 2; + sp++; + } + if (shift != 6) + *dp = (png_byte)v; + break; + } + case 4: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 4; + + sp++; + } + if (shift != 4) + *dp = (png_byte)v; + break; + } + } + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +void /* PRIVATE */ +png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift"); + + if ( + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + int channels = 0; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* With low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + png_uint_32 i; + png_byte mask; + png_uint_32 row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + png_uint_16 v; + int j; + + v = *bp; + *bp = 0; + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & mask); + } + } + } + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + + png_uint_16 v; + int j; + int c = (int)(i%channels); + + v = *bp; + *bp = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & 0xff); + } + } + } + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + int c = (int)(i%channels); + png_uint_16 value, v; + int j; + + v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + value = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); + else + value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + } + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from ARGB to RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AARRGGBB to RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from AG to GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AAGG to GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + } +} +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=3; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=6; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=2; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + } +} +#endif + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp+1))&0xff); + *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); + png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); + png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c new file mode 100644 index 00000000..19feb1d9 --- /dev/null +++ b/thirdparty/libpng/pngwutil.c @@ -0,0 +1,2786 @@ + +/* pngwutil.c - utilities to write a PNG file + * + * Last changed in libpng 1.4.1 [February 25, 2010] + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#define PNG_NO_PEDANTIC_WARNINGS +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED +#include "pngpriv.h" + +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void PNGAPI +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} + +#ifdef PNG_SAVE_INT_32_SUPPORTED +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. + */ +void PNGAPI +png_save_int_32(png_bytep buf, png_int_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void PNGAPI +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xff); + buf[1] = (png_byte)(i & 0xff); +} + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void PNGAPI +png_write_sig(png_structp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the signature is being written */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; +#endif + + /* Write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (png_size_t)(8 - png_ptr->sig_bytes)); + if (png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +void PNGAPI +png_write_chunk(png_structp png_ptr, png_bytep chunk_name, + png_bytep data, png_size_t length) +{ + if (png_ptr == NULL) + return; + png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, (png_size_t)length); + png_write_chunk_end(png_ptr); +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +void PNGAPI +png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, + png_uint_32 length) +{ + png_byte buf[8]; + + png_debug2(0, "Writing %s chunk, length = %lu", chunk_name, + (unsigned long)length); + + if (png_ptr == NULL) + return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being written. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; +#endif + + /* Write the length and the chunk name */ + png_save_uint_32(buf, length); + png_memcpy(buf + 4, chunk_name, 4); + png_write_data(png_ptr, buf, (png_size_t)8); + /* Put the chunk name into png_ptr->chunk_name */ + png_memcpy(png_ptr->chunk_name, chunk_name, 4); + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, chunk_name, 4); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be written. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; +#endif +} + +/* Write the data of a PNG chunk started with png_write_chunk_start(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_start(). + */ +void PNGAPI +png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + /* Write the data, and run the CRC over it */ + if (png_ptr == NULL) + return; + if (data != NULL && length > 0) + { + png_write_data(png_ptr, data, length); + /* Update the CRC after writing the data, + * in case that the user I/O routine alters it. + */ + png_calculate_crc(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_start(). */ +void PNGAPI +png_write_chunk_end(png_structp png_ptr) +{ + png_byte buf[4]; + + if (png_ptr == NULL) return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being written. + * PNG_IO_CHUNK_CRC requires a single I/O function call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; +#endif + + /* Write the crc in a single operation */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, (png_size_t)4); +} + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) +/* This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller in order to make the whole mess thread-safe. + */ + +typedef struct +{ + char *input; /* The uncompressed input data */ + int input_len; /* Its length */ + int num_output_ptr; /* Number of output pointers used */ + int max_output_ptr; /* Size of output_ptr */ + png_charpp output_ptr; /* Array of pointers to output */ +} compression_state; + +/* Compress given text into storage in the png_ptr structure */ +static int /* PRIVATE */ +png_text_compress(png_structp png_ptr, + png_charp text, png_size_t text_len, int compression, + compression_state *comp) +{ + int ret; + + comp->num_output_ptr = 0; + comp->max_output_ptr = 0; + comp->output_ptr = NULL; + comp->input = NULL; + comp->input_len = 0; + + /* We may just want to pass the text right through */ + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + comp->input = text; + comp->input_len = text_len; + return((int)text_len); + } + + if (compression >= PNG_TEXT_COMPRESSION_LAST) + { +#ifdef PNG_STDIO_SUPPORTED + char msg[50]; + png_snprintf(msg, 50, "Unknown compression type %d", compression); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "Unknown compression type"); +#endif + } + + /* We can't write the chunk until we find out how much data we have, + * which means we need to run the compressor first and save the + * output. This shouldn't be a problem, as the vast majority of + * comments should be reasonable, but we will set up an array of + * malloc'd pointers to be sure. + * + * If we knew the application was well behaved, we could simplify this + * greatly by assuming we can always malloc an output buffer large + * enough to hold the compressed text ((1001 * text_len / 1000) + 12) + * and malloc this directly. The only time this would be a bad idea is + * if we can't malloc more than 64K and we have 64K of random input + * data, or if the input string is incredibly large (although this + * wouldn't cause a failure, just a slowdown due to swapping). + */ + + /* Set up the compression buffers */ + png_ptr->zstream.avail_in = (uInt)text_len; + png_ptr->zstream.next_in = (Bytef *)text; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; + + /* This is the same compression loop as in png_write_row() */ + do + { + /* Compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + if (ret != Z_OK) + { + /* Error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + /* Check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* Make sure the output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_alloc_size_t) + (comp->max_output_ptr * png_sizeof(png_charpp))); + png_memcpy(comp->output_ptr, old_ptr, old_max + * png_sizeof(png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_alloc_size_t) + (comp->max_output_ptr * png_sizeof(png_charp))); + } + + /* Save the data */ + comp->output_ptr[comp->num_output_ptr] = + (png_charp)png_malloc(png_ptr, + (png_alloc_size_t)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + /* Continue until we don't have any more to compress */ + } while (png_ptr->zstream.avail_in); + + /* Finish the compression */ + do + { + /* Tell zlib we are finished */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + + if (ret == Z_OK) + { + /* Check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* Check to make sure our output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + /* This could be optimized to realloc() */ + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_alloc_size_t)(comp->max_output_ptr * + png_sizeof(png_charp))); + png_memcpy(comp->output_ptr, old_ptr, + old_max * png_sizeof(png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_alloc_size_t)(comp->max_output_ptr * + png_sizeof(png_charp))); + } + + /* Save the data */ + comp->output_ptr[comp->num_output_ptr] = + (png_charp)png_malloc(png_ptr, + (png_alloc_size_t)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer pointers */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + } + else if (ret != Z_STREAM_END) + { + /* We got an error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* Text length is number of buffers plus last buffer */ + text_len = png_ptr->zbuf_size * comp->num_output_ptr; + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; + + return((int)text_len); +} + +/* Ship the compressed text out via chunk writes */ +static void /* PRIVATE */ +png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) +{ + int i; + + /* Handle the no-compression case */ + if (comp->input) + { + png_write_chunk_data(png_ptr, (png_bytep)comp->input, + (png_size_t)comp->input_len); + return; + } + + /* Write saved output buffers, if any */ + for (i = 0; i < comp->num_output_ptr; i++) + { + png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i], + (png_size_t)png_ptr->zbuf_size); + png_free(png_ptr, comp->output_ptr[i]); + } + if (comp->max_output_ptr != 0) + png_free(png_ptr, comp->output_ptr); + /* Write anything left in zbuf */ + if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) + png_write_chunk_data(png_ptr, png_ptr->zbuf, + (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); + + /* Reset zlib for another zTXt/iTXt or image data */ + deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; +} +#endif + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ + PNG_IHDR; + int ret; + + png_byte buf[13]; /* Buffer to store the IHDR info */ + + png_debug(1, "in png_write_IHDR"); + + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + case 16: png_ptr->channels = 1; break; + default: png_error(png_ptr, + "Invalid bit depth for grayscale image"); + } + break; + case PNG_COLOR_TYPE_RGB: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGB image"); + png_ptr->channels = 3; + break; + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: png_ptr->channels = 1; break; + default: png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + png_ptr->channels = 2; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGBA image"); + png_ptr->channels = 4; + break; + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* Save the relevent information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); + /* Set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* Pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* Write the chunk */ + png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); + + /* Initialize zlib with PNG info */ + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + if (!(png_ptr->do_filter)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) + { + if (png_ptr->do_filter != PNG_FILTER_NONE) + png_ptr->zlib_strategy = Z_FILTERED; + else + png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) + png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) + png_ptr->zlib_mem_level = 8; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) + png_ptr->zlib_window_bits = 15; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) + png_ptr->zlib_method = 8; + ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, + png_ptr->zlib_method, png_ptr->zlib_window_bits, + png_ptr->zlib_mem_level, png_ptr->zlib_strategy); + if (ret != Z_OK) + { + if (ret == Z_VERSION_ERROR) png_error(png_ptr, + "zlib failed to initialize compressor -- version error"); + if (ret == Z_STREAM_ERROR) png_error(png_ptr, + "zlib failed to initialize compressor -- stream error"); + if (ret == Z_MEM_ERROR) png_error(png_ptr, + "zlib failed to initialize compressor -- mem error"); + png_error(png_ptr, "zlib failed to initialize compressor"); + } + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + /* libpng is not interested in zstream.data_type */ + /* Set it to a predefined value, to avoid its evaluation inside zlib */ + png_ptr->zstream.data_type = Z_BINARY; + + png_ptr->mode = PNG_HAVE_IHDR; +} + +/* Write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) +{ + PNG_PLTE; + png_uint_32 i; + png_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE"); + + if (( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && +#endif + num_pal == 0) || num_pal > 256) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d", png_ptr->num_palette); + + png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, + (png_uint_32)(num_pal * 3)); +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#else + /* This is a little slower but some buggy compilers need to do this + * instead + */ + pal_ptr=palette; + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* Write an IDAT chunk */ +void /* PRIVATE */ +png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +{ + PNG_IDAT; + + png_debug(1, "in png_write_IDAT"); + + /* Optimize the CMF field in the zlib stream. */ + /* This hack of the zlib stream is compliant to the stream specification. */ + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + /* Avoid memory underflows and multiplication overflows. + * + * The conditions below are practically always satisfied; + * however, they still must be checked. + */ + if (length >= 2 && + png_ptr->height < 16384 && png_ptr->width < 16384) + { + png_uint_32 uncompressed_idat_size = png_ptr->height * + ((png_ptr->width * + png_ptr->channels * png_ptr->bit_depth + 15) >> 3); + unsigned int z_cinfo = z_cmf >> 4; + unsigned int half_z_window_size = 1 << (z_cinfo + 7); + while (uncompressed_idat_size <= half_z_window_size && + half_z_window_size >= 256) + { + z_cinfo--; + half_z_window_size >>= 1; + } + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + if (data[0] != (png_byte)z_cmf) + { + data[0] = (png_byte)z_cmf; + data[1] &= 0xe0; + data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); + } + } + } + else + png_error(png_ptr, + "Invalid zlib compression method or flags in IDAT"); + } + + png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); + png_ptr->mode |= PNG_HAVE_IDAT; +} + +/* Write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structp png_ptr) +{ + PNG_IEND; + + png_debug(1, "in png_write_IEND"); + + png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, + (png_size_t)0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#ifdef PNG_WRITE_gAMA_SUPPORTED +/* Write a gAMA chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA(png_structp png_ptr, double file_gamma) +{ + PNG_gAMA; + png_uint_32 igamma; + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); + png_save_uint_32(buf, igamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +{ + PNG_gAMA; + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, (png_uint_32)file_gamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +/* Write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structp png_ptr, int srgb_intent) +{ + PNG_sRGB; + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB"); + + if (srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + buf[0]=(png_byte)srgb_intent; + png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); +} +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +/* Write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, + png_charp profile, int profile_len) +{ + PNG_iCCP; + png_size_t name_len; + png_charp new_name; + compression_state comp; + int embedded_profile_len = 0; + + png_debug(1, "in png_write_iCCP"); + + comp.num_output_ptr = 0; + comp.max_output_ptr = 0; + comp.output_ptr = NULL; + comp.input = NULL; + comp.input_len = 0; + + if ((name_len = png_check_keyword(png_ptr, name, + &new_name)) == 0) + return; + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_warning(png_ptr, "Unknown compression type in iCCP chunk"); + + if (profile == NULL) + profile_len = 0; + + if (profile_len > 3) + embedded_profile_len = + ((*( (png_bytep)profile ))<<24) | + ((*( (png_bytep)profile + 1))<<16) | + ((*( (png_bytep)profile + 2))<< 8) | + ((*( (png_bytep)profile + 3)) ); + + if (embedded_profile_len < 0) + { + png_warning(png_ptr, + "Embedded profile length in iCCP chunk is negative"); + png_free(png_ptr, new_name); + return; + } + + if (profile_len < embedded_profile_len) + { + png_warning(png_ptr, + "Embedded profile length too large in iCCP chunk"); + png_free(png_ptr, new_name); + return; + } + + if (profile_len > embedded_profile_len) + { + png_warning(png_ptr, + "Truncating profile to actual length in iCCP chunk"); + profile_len = embedded_profile_len; + } + + if (profile_len) + profile_len = png_text_compress(png_ptr, profile, + (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); + + /* Make sure we include the NULL after the name and the compression type */ + png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, + (png_uint_32)(name_len + profile_len + 2)); + new_name[name_len + 1] = 0x00; + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 2)); + + if (profile_len) + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +/* Write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) +{ + PNG_sPLT; + png_size_t name_len; + png_charp new_name; + png_byte entrybuf[10]; + png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); + png_size_t palette_size = entry_size * spalette->nentries; + png_sPLT_entryp ep; +#ifndef PNG_POINTER_INDEXING_SUPPORTED + int i; +#endif + + png_debug(1, "in png_write_sPLT"); + + if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) + return; + + /* Make sure we include the NULL after the name */ + png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 1)); + png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1); + + /* Loop through each palette entry, writing appropriately */ +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (ep = spalette->entries; epentries + spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + } +#else + ep=spalette->entries; + for (i=0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + } +#endif + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +/* Write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) +{ + PNG_sBIT; + png_byte buf[4]; + png_size_t size; + + png_debug(1, "in png_write_sBIT"); + + /* Make sure we don't depend upon the order of PNG_COLOR_8 */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->gray; + size = 1; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[size++] = sbit->alpha; + } + + png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); +} +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +/* Write the cHRM chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM(png_structp png_ptr, double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y) +{ + PNG_cHRM; + png_byte buf[32]; + + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, + int_green_x, int_green_y, int_blue_x, int_blue_y; + + png_debug(1, "in png_write_cHRM"); + + int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5); + int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5); + int_red_x = (png_uint_32)(red_x * 100000.0 + 0.5); + int_red_y = (png_uint_32)(red_y * 100000.0 + 0.5); + int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5); + int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5); + int_blue_x = (png_uint_32)(blue_x * 100000.0 + 0.5); + int_blue_y = (png_uint_32)(blue_y * 100000.0 + 0.5); + +#ifdef PNG_CHECK_cHRM_SUPPORTED + if (png_check_cHRM_fixed(png_ptr, int_white_x, int_white_y, + int_red_x, int_red_y, int_green_x, int_green_y, int_blue_x, int_blue_y)) +#endif + { + /* Each value is saved in 1/100,000ths */ + + png_save_uint_32(buf, int_white_x); + png_save_uint_32(buf + 4, int_white_y); + + png_save_uint_32(buf + 8, int_red_x); + png_save_uint_32(buf + 12, int_red_y); + + png_save_uint_32(buf + 16, int_green_x); + png_save_uint_32(buf + 20, int_green_y); + + png_save_uint_32(buf + 24, int_blue_x); + png_save_uint_32(buf + 28, int_blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); + } +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, + png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, + png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, + png_fixed_point blue_y) +{ + PNG_cHRM; + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM"); + + /* Each value is saved in 1/100,000ths */ +#ifdef PNG_CHECK_cHRM_SUPPORTED + if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, + green_x, green_y, blue_x, blue_y)) +#endif + { + png_save_uint_32(buf, (png_uint_32)white_x); + png_save_uint_32(buf + 4, (png_uint_32)white_y); + + png_save_uint_32(buf + 8, (png_uint_32)red_x); + png_save_uint_32(buf + 12, (png_uint_32)red_y); + + png_save_uint_32(buf + 16, (png_uint_32)green_x); + png_save_uint_32(buf + 20, (png_uint_32)green_y); + + png_save_uint_32(buf + 24, (png_uint_32)blue_x); + png_save_uint_32(buf + 28, (png_uint_32)blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); + } +} +#endif +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +/* Write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structp png_ptr, png_bytep trans_alpha, png_color_16p tran, + int num_trans, int color_type) +{ + PNG_tRNS; + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid number of transparent colors specified"); + return; + } + /* Write the chunk out as it is */ + png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans_alpha, + (png_size_t)num_trans); + } + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* One 16 bit value */ + if (tran->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + return; + } + png_save_uint_16(buf, tran->gray); + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); + } + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* Three 16 bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + return; + } + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); + } + else + { + png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +/* Write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) +{ + PNG_bKGD; + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->num_palette || + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && +#endif + back->index >= png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + buf[0] = back->index; + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); + } + else if (color_type & PNG_COLOR_MASK_COLOR) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + return; + } + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); + } + else + { + if (back->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + return; + } + png_save_uint_16(buf, back->gray); + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); + } +} +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +/* Write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) +{ + PNG_hIST; + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST"); + + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, + png_ptr->num_palette); + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_start(png_ptr, (png_bytep)png_hIST, + (png_uint_32)(num_hist * 2)); + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); + } + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The new_key is allocated to hold the corrected keyword and must be freed + * by the calling routine. This avoids problems with trying to write to + * static keywords without having to have duplicate copies of the strings. + */ +png_size_t /* PRIVATE */ +png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) +{ + png_size_t key_len; + png_charp kp, dp; + int kflag; + int kwarn=0; + + png_debug(1, "in png_check_keyword"); + + *new_key = NULL; + + if (key == NULL || (key_len = png_strlen(key)) == 0) + { + png_warning(png_ptr, "zero length keyword"); + return ((png_size_t)0); + } + + png_debug1(2, "Keyword to be checked is '%s'", key); + + *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); + if (*new_key == NULL) + { + png_warning(png_ptr, "Out of memory while procesing keyword"); + return ((png_size_t)0); + } + + /* Replace non-printing characters with a blank and print a warning */ + for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) + { + if ((png_byte)*kp < 0x20 || + ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) + { +#ifdef PNG_STDIO_SUPPORTED + char msg[40]; + + png_snprintf(msg, 40, + "invalid keyword character 0x%02X", (png_byte)*kp); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "invalid character in keyword"); +#endif + *dp = ' '; + } + else + { + *dp = *kp; + } + } + *dp = '\0'; + + /* Remove any trailing white space. */ + kp = *new_key + key_len - 1; + if (*kp == ' ') + { + png_warning(png_ptr, "trailing spaces removed from keyword"); + + while (*kp == ' ') + { + *(kp--) = '\0'; + key_len--; + } + } + + /* Remove any leading white space. */ + kp = *new_key; + if (*kp == ' ') + { + png_warning(png_ptr, "leading spaces removed from keyword"); + + while (*kp == ' ') + { + kp++; + key_len--; + } + } + + png_debug1(2, "Checking for multiple internal spaces in '%s'", kp); + + /* Remove multiple internal spaces. */ + for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) + { + if (*kp == ' ' && kflag == 0) + { + *(dp++) = *kp; + kflag = 1; + } + else if (*kp == ' ') + { + key_len--; + kwarn=1; + } + else + { + *(dp++) = *kp; + kflag = 0; + } + } + *dp = '\0'; + if (kwarn) + png_warning(png_ptr, "extra interior spaces removed from keyword"); + + if (key_len == 0) + { + png_free(png_ptr, *new_key); + png_warning(png_ptr, "Zero length keyword"); + } + + if (key_len > 79) + { + png_warning(png_ptr, "keyword length must be 1 - 79 characters"); + (*new_key)[79] = '\0'; + key_len = 79; + } + + return (key_len); +} +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +/* Write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len) +{ + PNG_tEXt; + png_size_t key_len; + png_charp new_key; + + png_debug(1, "in png_write_tEXt"); + + if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + return; + + if (text == NULL || *text == '\0') + text_len = 0; + else + text_len = png_strlen(text); + + /* Make sure we include the 0 after the key */ + png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, + (png_uint_32)(key_len + text_len + 1)); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, + (png_size_t)(key_len + 1)); + if (text_len) + png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); +} +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +/* Write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len, int compression) +{ + PNG_zTXt; + png_size_t key_len; + char buf[1]; + png_charp new_key; + compression_state comp; + + png_debug(1, "in png_write_zTXt"); + + comp.num_output_ptr = 0; + comp.max_output_ptr = 0; + comp.output_ptr = NULL; + comp.input = NULL; + comp.input_len = 0; + + if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_free(png_ptr, new_key); + return; + } + + if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); + png_free(png_ptr, new_key); + return; + } + + text_len = png_strlen(text); + + /* Compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression, + &comp); + + /* Write start of chunk */ + png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, + (png_uint_32)(key_len+text_len + 2)); + /* Write key */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, + (png_size_t)(key_len + 1)); + png_free(png_ptr, new_key); + + buf[0] = (png_byte)compression; + /* Write compression */ + png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); + /* Write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* Close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +/* Write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structp png_ptr, int compression, png_charp key, + png_charp lang, png_charp lang_key, png_charp text) +{ + PNG_iTXt; + png_size_t lang_len, key_len, lang_key_len, text_len; + png_charp new_lang; + png_charp new_key = NULL; + png_byte cbuf[2]; + compression_state comp; + + png_debug(1, "in png_write_iTXt"); + + comp.num_output_ptr = 0; + comp.max_output_ptr = 0; + comp.output_ptr = NULL; + comp.input = NULL; + + if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + return; + + if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) + { + png_warning(png_ptr, "Empty language field in iTXt chunk"); + new_lang = NULL; + lang_len = 0; + } + + if (lang_key == NULL) + lang_key_len = 0; + else + lang_key_len = png_strlen(lang_key); + + if (text == NULL) + text_len = 0; + else + text_len = png_strlen(text); + + /* Compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression-2, + &comp); + + + /* Make sure we include the compression flag, the compression byte, + * and the NULs after the key, lang, and lang_key parts */ + + png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, + (png_uint_32)( + 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ + + key_len + + lang_len + + lang_key_len + + text_len)); + + /* We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, + (png_size_t)(key_len + 1)); + + /* Set the compression flag */ + if (compression == PNG_ITXT_COMPRESSION_NONE || \ + compression == PNG_TEXT_COMPRESSION_NONE) + cbuf[0] = 0; + else /* compression == PNG_ITXT_COMPRESSION_zTXt */ + cbuf[0] = 1; + /* Set the compression method */ + cbuf[1] = 0; + png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); + + cbuf[0] = 0; + png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), + (png_size_t)(lang_len + 1)); + png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), + (png_size_t)(lang_key_len + 1)); + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); + png_free(png_ptr, new_lang); +} +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +/* Write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) +{ + PNG_oFFs; + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs"); + + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_int_32(buf, x_offset); + png_save_int_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); +} +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED +/* Write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) +{ + PNG_pCAL; + png_size_t purpose_len, units_len, total_len; + png_uint_32p params_len; + png_byte buf[10]; + png_charp new_purpose; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); + + if (type >= PNG_EQUATION_LAST) + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; + png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); + units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (png_uint_32p)png_malloc(png_ptr, + (png_alloc_size_t)(nparams * png_sizeof(png_uint_32))); + + /* Find the length of each parameter, making sure we don't count the + null terminator for the last parameter. */ + for (i = 0; i < nparams; i++) + { + params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu", i, + (unsigned long) params_len[i]); + total_len += (png_size_t)params_len[i]; + } + + png_debug1(3, "pCAL total length = %d", (int)total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)new_purpose, + (png_size_t)purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); + + png_free(png_ptr, new_purpose); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_bytep)params[i], + (png_size_t)params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +/* Write the sCAL chunk */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +void /* PRIVATE */ +png_write_sCAL(png_structp png_ptr, int unit, double width, double height) +{ + PNG_sCAL; + char buf[64]; + png_size_t total_len; + + png_debug(1, "in png_write_sCAL"); + + buf[0] = (char)unit; + png_snprintf(buf + 1, 63, "%12.12e", width); + total_len = 1 + png_strlen(buf + 1) + 1; + png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); + total_len += png_strlen(buf + total_len); + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, + png_charp height) +{ + PNG_sCAL; + png_byte buf[64]; + png_size_t wlen, hlen, total_len; + + png_debug(1, "in png_write_sCAL_s"); + + wlen = png_strlen(width); + hlen = png_strlen(height); + total_len = wlen + hlen + 2; + if (total_len > 64) + { + png_warning(png_ptr, "Can't write sCAL (buffer too small)"); + return; + } + + buf[0] = (png_byte)unit; + png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len); +} +#endif +#endif +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +/* Write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ + PNG_pHYs; + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs"); + + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); +} +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structp png_ptr, png_timep mod_time) +{ + PNG_tIME; + png_byte buf[7]; + + png_debug(1, "in png_write_tIME"); + + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); +} +#endif + +/* Initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_size_t buf_size; + + png_debug(1, "in png_write_start_row"); + + buf_size = (png_size_t)(PNG_ROWBYTES( + png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); + + /* Set up row buffer */ + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)buf_size); + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* Set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)(png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + /* We only need to keep the previous row if we are using one of these. */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* Set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, + (png_alloc_size_t)buf_size); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_size_t)(png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)(png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_size_t)(png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int ret; + + png_debug(1, "in png_write_finish_row"); + + /* Next row */ + png_ptr->row_number++; + + /* See if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, go to next pass */ + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + if (png_ptr->transformations & PNG_INTERLACE) + { + png_ptr->pass++; + } + else + { + /* Loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (png_ptr->transformations & PNG_INTERLACE) + break; + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* Reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + png_memset(png_ptr->prev_row, 0, + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth, png_ptr->width)) + 1); + return; + } + } +#endif + + /* If we get here, we've just written the last row, so we need + to flush the compressor */ + do + { + /* Tell the compressor we are done */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + /* Check for an error */ + if (ret == Z_OK) + { + /* Check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else if (ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* Write any extra space */ + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - + png_ptr->zstream.avail_out); + } + + deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; +} + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_write_interlace"); + + /* We don't have to do anything on the last pass (6) */ + if (pass < 6) + { + /* Each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + break; + } + case 2: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + break; + } + case 4: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + break; + } + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + png_size_t pixel_bytes; + + /* Start at the beginning */ + dp = row; + /* Find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + /* Loop through the row, only looking at the pixels that + matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* Find out where the original pixel is */ + sp = row + (png_size_t)i * pixel_bytes; + /* Move the pixel */ + if (dp != sp) + png_memcpy(dp, sp, pixel_bytes); + /* Next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* Set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) +#define PNG_HISHIFT 10 +#define PNG_LOMASK ((png_uint_32)0xffffL) +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) +void /* PRIVATE */ +png_write_find_filter(png_structp png_ptr, png_row_infop row_info) +{ + png_bytep best_row; +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_bytep prev_row, row_buf; + png_uint_32 mins, bpp; + png_byte filter_to_do = png_ptr->do_filter; + png_uint_32 row_bytes = row_info->rowbytes; +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + int num_p_filters = (int)png_ptr->num_prev_filters; +#endif + + png_debug(1, "in png_write_find_filter"); + +#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) + { + /* These will never be selected so we need not test them. */ + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); + } +#endif + + /* Find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) >> 3; + + prev_row = png_ptr->prev_row; +#endif + best_row = png_ptr->row_buf; +#ifdef PNG_WRITE_FILTER_SUPPORTED + row_buf = best_row; + mins = PNG_MAXSUM; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + if ((filter_to_do & PNG_FILTER_NONE) && + filter_to_do != PNG_FILTER_NONE) + { + png_bytep rp; + png_uint_32 sum = 0; + png_uint_32 i; + int v; + + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + png_uint_32 sumhi, sumlo; + int j; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ + + /* Reduce the sum if we match any of the previous rows */ + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + /* Factor in the cost of this filter (this is here for completeness, + * but it makes no sense to have a "cost" for the NONE filter, as + * it has the minimum possible computational cost - none). + */ + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + mins = sum; + } + + /* Sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* It's the only filter so no testing is needed */ + { + png_bytep rp, lp, dp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } + best_row = png_ptr->sub_row; + } + + else if (filter_to_do & PNG_FILTER_SUB) + { + png_bytep rp, dp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* We temporarily increase the "minimum sum" by the factor we + * would reduce the sum of this filter, so that we can do the + * early exit comparison without scaling the sum each time. + */ + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->sub_row; + } + } + + /* Up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } + best_row = png_ptr->up_row; + } + + else if (filter_to_do & PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->up_row; + } + } + + /* Avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } + best_row = png_ptr->avg_row; + } + + else if (filter_to_do & PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->avg_row; + } + } + + /* Paeth filter */ + if (filter_to_do == PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } + best_row = png_ptr->paeth_row; + } + + else if (filter_to_do & PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + +#ifndef PNG_SLOW_PAETH + p = b - c; + pc = a - c; +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; +#else /* PNG_SLOW_PAETH */ + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; +#endif /* PNG_SLOW_PAETH */ + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + best_row = png_ptr->paeth_row; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + /* Do the actual writing of the filtered row data from the chosen filter. */ + + png_write_filtered_row(png_ptr, best_row); + +#ifdef PNG_WRITE_FILTER_SUPPORTED +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* Save the type of filter we picked this time for future calculations */ + if (png_ptr->num_prev_filters > 0) + { + int j; + for (j = 1; j < num_p_filters; j++) + { + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; + } + png_ptr->prev_filters[j] = best_row[0]; + } +#endif +#endif /* PNG_WRITE_FILTER_SUPPORTED */ +} + + +/* Do the actual writing of a previously filtered row. */ +void /* PRIVATE */ +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +{ + png_debug(1, "in png_write_filtered_row"); + + png_debug1(2, "filter = %d", filtered_row[0]); + /* Set up the zlib input buffer */ + + png_ptr->zstream.next_in = filtered_row; + png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; + /* Repeat until we have compressed all the data */ + do + { + int ret; /* Return of zlib */ + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + /* Check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + /* See if it is time to write another IDAT */ + if (!(png_ptr->zstream.avail_out)) + { + /* Write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + /* Repeat until all data has been compressed */ + } while (png_ptr->zstream.avail_in); + + /* Swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } + + /* Finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif +} +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/thirdparty/libtiff/CMakeLists.txt b/thirdparty/libtiff/CMakeLists.txt new file mode 100644 index 00000000..851c9573 --- /dev/null +++ b/thirdparty/libtiff/CMakeLists.txt @@ -0,0 +1,79 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +project(libtiff C) + +INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}") +# +ADD_DEFINITIONS(-DHAVE_STRING_H=1) + +SET(TARGET_FILES + t4.h + tiffiop.h + tif_aux.c + tif_close.c + tif_codec.c + tif_color.c + tif_compress.c + tif_dir.c + tif_dir.h + tif_dirinfo.c + tif_dirread.c + tif_dirwrite.c + tif_dumpmode.c + tif_error.c + tif_extension.c + tif_fax3.c + tif_fax3.h + tif_fax3sm.c + tif_flush.c + tif_getimage.c + tif_jbig.c + tif_jpeg.c + tif_luv.c + tif_lzw.c + tif_next.c + tif_ojpeg.c + tif_open.c + tif_packbits.c + tif_pixarlog.c + tif_predict.c + tif_predict.h + tif_print.c + tif_read.c + tif_stream.cxx + tif_strip.c + tif_swab.c + tif_thunder.c + tif_tile.c + tif_version.c + tif_warning.c + tif_write.c + tif_zip.c + uvcode.h + ) + +IF(UNIX) + SET(TARGET_FILES ${TARGET_FILES} tif_unix.c) +ENDIF() + +IF(WIN32) + SET(TARGET_FILES ${TARGET_FILES} tif_win32.c) +ENDIF(WIN32) + +#IF(APPLE) +# SET(TARGET_FILES ${TARGET_FILES} tif_apple.c) +#ENDIF(APPLE) + +SET(LIBTARGET "tiff") +# +ADD_LIBRARY(${LIBTARGET} STATIC ${TARGET_FILES}) +# +IF(MSVC) + SET_TARGET_PROPERTIES(${LIBTARGET} PROPERTIES PREFIX "lib") +ENDIF(MSVC) +# +SET_TARGET_PROPERTIES(${LIBTARGET} + PROPERTIES + OUTPUT_NAME "${LIBTARGET}" + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/thirdparty/lib +) +# diff --git a/thirdparty/libtiff/t4.h b/thirdparty/libtiff/t4.h new file mode 100644 index 00000000..870704ff --- /dev/null +++ b/thirdparty/libtiff/t4.h @@ -0,0 +1,292 @@ +/* $Id: t4.h,v 1.1.1.1.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _T4_ +#define _T4_ +/* + * CCITT T.4 1D Huffman runlength codes and + * related definitions. Given the small sizes + * of these tables it does not seem + * worthwhile to make code & length 8 bits. + */ +typedef struct tableentry { + unsigned short length; /* bit length of g3 code */ + unsigned short code; /* g3 code */ + short runlen; /* run length in bits */ +} tableentry; + +#define EOL 0x001 /* EOL code value - 0000 0000 0000 1 */ + +/* status values returned instead of a run length */ +#define G3CODE_EOL -1 /* NB: ACT_EOL - ACT_WRUNT */ +#define G3CODE_INVALID -2 /* NB: ACT_INVALID - ACT_WRUNT */ +#define G3CODE_EOF -3 /* end of input data */ +#define G3CODE_INCOMP -4 /* incomplete run code */ + +/* + * Note that these tables are ordered such that the + * index into the table is known to be either the + * run length, or (run length / 64) + a fixed offset. + * + * NB: The G3CODE_INVALID entries are only used + * during state generation (see mkg3states.c). + */ +#ifdef G3CODES +const tableentry TIFFFaxWhiteCodes[] = { + { 8, 0x35, 0 }, /* 0011 0101 */ + { 6, 0x7, 1 }, /* 0001 11 */ + { 4, 0x7, 2 }, /* 0111 */ + { 4, 0x8, 3 }, /* 1000 */ + { 4, 0xB, 4 }, /* 1011 */ + { 4, 0xC, 5 }, /* 1100 */ + { 4, 0xE, 6 }, /* 1110 */ + { 4, 0xF, 7 }, /* 1111 */ + { 5, 0x13, 8 }, /* 1001 1 */ + { 5, 0x14, 9 }, /* 1010 0 */ + { 5, 0x7, 10 }, /* 0011 1 */ + { 5, 0x8, 11 }, /* 0100 0 */ + { 6, 0x8, 12 }, /* 0010 00 */ + { 6, 0x3, 13 }, /* 0000 11 */ + { 6, 0x34, 14 }, /* 1101 00 */ + { 6, 0x35, 15 }, /* 1101 01 */ + { 6, 0x2A, 16 }, /* 1010 10 */ + { 6, 0x2B, 17 }, /* 1010 11 */ + { 7, 0x27, 18 }, /* 0100 111 */ + { 7, 0xC, 19 }, /* 0001 100 */ + { 7, 0x8, 20 }, /* 0001 000 */ + { 7, 0x17, 21 }, /* 0010 111 */ + { 7, 0x3, 22 }, /* 0000 011 */ + { 7, 0x4, 23 }, /* 0000 100 */ + { 7, 0x28, 24 }, /* 0101 000 */ + { 7, 0x2B, 25 }, /* 0101 011 */ + { 7, 0x13, 26 }, /* 0010 011 */ + { 7, 0x24, 27 }, /* 0100 100 */ + { 7, 0x18, 28 }, /* 0011 000 */ + { 8, 0x2, 29 }, /* 0000 0010 */ + { 8, 0x3, 30 }, /* 0000 0011 */ + { 8, 0x1A, 31 }, /* 0001 1010 */ + { 8, 0x1B, 32 }, /* 0001 1011 */ + { 8, 0x12, 33 }, /* 0001 0010 */ + { 8, 0x13, 34 }, /* 0001 0011 */ + { 8, 0x14, 35 }, /* 0001 0100 */ + { 8, 0x15, 36 }, /* 0001 0101 */ + { 8, 0x16, 37 }, /* 0001 0110 */ + { 8, 0x17, 38 }, /* 0001 0111 */ + { 8, 0x28, 39 }, /* 0010 1000 */ + { 8, 0x29, 40 }, /* 0010 1001 */ + { 8, 0x2A, 41 }, /* 0010 1010 */ + { 8, 0x2B, 42 }, /* 0010 1011 */ + { 8, 0x2C, 43 }, /* 0010 1100 */ + { 8, 0x2D, 44 }, /* 0010 1101 */ + { 8, 0x4, 45 }, /* 0000 0100 */ + { 8, 0x5, 46 }, /* 0000 0101 */ + { 8, 0xA, 47 }, /* 0000 1010 */ + { 8, 0xB, 48 }, /* 0000 1011 */ + { 8, 0x52, 49 }, /* 0101 0010 */ + { 8, 0x53, 50 }, /* 0101 0011 */ + { 8, 0x54, 51 }, /* 0101 0100 */ + { 8, 0x55, 52 }, /* 0101 0101 */ + { 8, 0x24, 53 }, /* 0010 0100 */ + { 8, 0x25, 54 }, /* 0010 0101 */ + { 8, 0x58, 55 }, /* 0101 1000 */ + { 8, 0x59, 56 }, /* 0101 1001 */ + { 8, 0x5A, 57 }, /* 0101 1010 */ + { 8, 0x5B, 58 }, /* 0101 1011 */ + { 8, 0x4A, 59 }, /* 0100 1010 */ + { 8, 0x4B, 60 }, /* 0100 1011 */ + { 8, 0x32, 61 }, /* 0011 0010 */ + { 8, 0x33, 62 }, /* 0011 0011 */ + { 8, 0x34, 63 }, /* 0011 0100 */ + { 5, 0x1B, 64 }, /* 1101 1 */ + { 5, 0x12, 128 }, /* 1001 0 */ + { 6, 0x17, 192 }, /* 0101 11 */ + { 7, 0x37, 256 }, /* 0110 111 */ + { 8, 0x36, 320 }, /* 0011 0110 */ + { 8, 0x37, 384 }, /* 0011 0111 */ + { 8, 0x64, 448 }, /* 0110 0100 */ + { 8, 0x65, 512 }, /* 0110 0101 */ + { 8, 0x68, 576 }, /* 0110 1000 */ + { 8, 0x67, 640 }, /* 0110 0111 */ + { 9, 0xCC, 704 }, /* 0110 0110 0 */ + { 9, 0xCD, 768 }, /* 0110 0110 1 */ + { 9, 0xD2, 832 }, /* 0110 1001 0 */ + { 9, 0xD3, 896 }, /* 0110 1001 1 */ + { 9, 0xD4, 960 }, /* 0110 1010 0 */ + { 9, 0xD5, 1024 }, /* 0110 1010 1 */ + { 9, 0xD6, 1088 }, /* 0110 1011 0 */ + { 9, 0xD7, 1152 }, /* 0110 1011 1 */ + { 9, 0xD8, 1216 }, /* 0110 1100 0 */ + { 9, 0xD9, 1280 }, /* 0110 1100 1 */ + { 9, 0xDA, 1344 }, /* 0110 1101 0 */ + { 9, 0xDB, 1408 }, /* 0110 1101 1 */ + { 9, 0x98, 1472 }, /* 0100 1100 0 */ + { 9, 0x99, 1536 }, /* 0100 1100 1 */ + { 9, 0x9A, 1600 }, /* 0100 1101 0 */ + { 6, 0x18, 1664 }, /* 0110 00 */ + { 9, 0x9B, 1728 }, /* 0100 1101 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; + +const tableentry TIFFFaxBlackCodes[] = { + { 10, 0x37, 0 }, /* 0000 1101 11 */ + { 3, 0x2, 1 }, /* 010 */ + { 2, 0x3, 2 }, /* 11 */ + { 2, 0x2, 3 }, /* 10 */ + { 3, 0x3, 4 }, /* 011 */ + { 4, 0x3, 5 }, /* 0011 */ + { 4, 0x2, 6 }, /* 0010 */ + { 5, 0x3, 7 }, /* 0001 1 */ + { 6, 0x5, 8 }, /* 0001 01 */ + { 6, 0x4, 9 }, /* 0001 00 */ + { 7, 0x4, 10 }, /* 0000 100 */ + { 7, 0x5, 11 }, /* 0000 101 */ + { 7, 0x7, 12 }, /* 0000 111 */ + { 8, 0x4, 13 }, /* 0000 0100 */ + { 8, 0x7, 14 }, /* 0000 0111 */ + { 9, 0x18, 15 }, /* 0000 1100 0 */ + { 10, 0x17, 16 }, /* 0000 0101 11 */ + { 10, 0x18, 17 }, /* 0000 0110 00 */ + { 10, 0x8, 18 }, /* 0000 0010 00 */ + { 11, 0x67, 19 }, /* 0000 1100 111 */ + { 11, 0x68, 20 }, /* 0000 1101 000 */ + { 11, 0x6C, 21 }, /* 0000 1101 100 */ + { 11, 0x37, 22 }, /* 0000 0110 111 */ + { 11, 0x28, 23 }, /* 0000 0101 000 */ + { 11, 0x17, 24 }, /* 0000 0010 111 */ + { 11, 0x18, 25 }, /* 0000 0011 000 */ + { 12, 0xCA, 26 }, /* 0000 1100 1010 */ + { 12, 0xCB, 27 }, /* 0000 1100 1011 */ + { 12, 0xCC, 28 }, /* 0000 1100 1100 */ + { 12, 0xCD, 29 }, /* 0000 1100 1101 */ + { 12, 0x68, 30 }, /* 0000 0110 1000 */ + { 12, 0x69, 31 }, /* 0000 0110 1001 */ + { 12, 0x6A, 32 }, /* 0000 0110 1010 */ + { 12, 0x6B, 33 }, /* 0000 0110 1011 */ + { 12, 0xD2, 34 }, /* 0000 1101 0010 */ + { 12, 0xD3, 35 }, /* 0000 1101 0011 */ + { 12, 0xD4, 36 }, /* 0000 1101 0100 */ + { 12, 0xD5, 37 }, /* 0000 1101 0101 */ + { 12, 0xD6, 38 }, /* 0000 1101 0110 */ + { 12, 0xD7, 39 }, /* 0000 1101 0111 */ + { 12, 0x6C, 40 }, /* 0000 0110 1100 */ + { 12, 0x6D, 41 }, /* 0000 0110 1101 */ + { 12, 0xDA, 42 }, /* 0000 1101 1010 */ + { 12, 0xDB, 43 }, /* 0000 1101 1011 */ + { 12, 0x54, 44 }, /* 0000 0101 0100 */ + { 12, 0x55, 45 }, /* 0000 0101 0101 */ + { 12, 0x56, 46 }, /* 0000 0101 0110 */ + { 12, 0x57, 47 }, /* 0000 0101 0111 */ + { 12, 0x64, 48 }, /* 0000 0110 0100 */ + { 12, 0x65, 49 }, /* 0000 0110 0101 */ + { 12, 0x52, 50 }, /* 0000 0101 0010 */ + { 12, 0x53, 51 }, /* 0000 0101 0011 */ + { 12, 0x24, 52 }, /* 0000 0010 0100 */ + { 12, 0x37, 53 }, /* 0000 0011 0111 */ + { 12, 0x38, 54 }, /* 0000 0011 1000 */ + { 12, 0x27, 55 }, /* 0000 0010 0111 */ + { 12, 0x28, 56 }, /* 0000 0010 1000 */ + { 12, 0x58, 57 }, /* 0000 0101 1000 */ + { 12, 0x59, 58 }, /* 0000 0101 1001 */ + { 12, 0x2B, 59 }, /* 0000 0010 1011 */ + { 12, 0x2C, 60 }, /* 0000 0010 1100 */ + { 12, 0x5A, 61 }, /* 0000 0101 1010 */ + { 12, 0x66, 62 }, /* 0000 0110 0110 */ + { 12, 0x67, 63 }, /* 0000 0110 0111 */ + { 10, 0xF, 64 }, /* 0000 0011 11 */ + { 12, 0xC8, 128 }, /* 0000 1100 1000 */ + { 12, 0xC9, 192 }, /* 0000 1100 1001 */ + { 12, 0x5B, 256 }, /* 0000 0101 1011 */ + { 12, 0x33, 320 }, /* 0000 0011 0011 */ + { 12, 0x34, 384 }, /* 0000 0011 0100 */ + { 12, 0x35, 448 }, /* 0000 0011 0101 */ + { 13, 0x6C, 512 }, /* 0000 0011 0110 0 */ + { 13, 0x6D, 576 }, /* 0000 0011 0110 1 */ + { 13, 0x4A, 640 }, /* 0000 0010 0101 0 */ + { 13, 0x4B, 704 }, /* 0000 0010 0101 1 */ + { 13, 0x4C, 768 }, /* 0000 0010 0110 0 */ + { 13, 0x4D, 832 }, /* 0000 0010 0110 1 */ + { 13, 0x72, 896 }, /* 0000 0011 1001 0 */ + { 13, 0x73, 960 }, /* 0000 0011 1001 1 */ + { 13, 0x74, 1024 }, /* 0000 0011 1010 0 */ + { 13, 0x75, 1088 }, /* 0000 0011 1010 1 */ + { 13, 0x76, 1152 }, /* 0000 0011 1011 0 */ + { 13, 0x77, 1216 }, /* 0000 0011 1011 1 */ + { 13, 0x52, 1280 }, /* 0000 0010 1001 0 */ + { 13, 0x53, 1344 }, /* 0000 0010 1001 1 */ + { 13, 0x54, 1408 }, /* 0000 0010 1010 0 */ + { 13, 0x55, 1472 }, /* 0000 0010 1010 1 */ + { 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */ + { 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */ + { 13, 0x64, 1664 }, /* 0000 0011 0010 0 */ + { 13, 0x65, 1728 }, /* 0000 0011 0010 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; +#else +extern const tableentry TIFFFaxWhiteCodes[]; +extern const tableentry TIFFFaxBlackCodes[]; +#endif +#endif /* _T4_ */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_apple.c b/thirdparty/libtiff/tif_apple.c new file mode 100644 index 00000000..8c482288 --- /dev/null +++ b/thirdparty/libtiff/tif_apple.c @@ -0,0 +1,281 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Attic/tif_apple.c,v 1.3.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Macintosh-specific routines. + * + * These routines use only Toolbox and high-level File Manager traps. + * They make no calls to the THINK C "unix" compatibility library. Also, + * malloc is not used directly but it is still referenced internally by + * the ANSI library in rare cases. Heap fragmentation by the malloc ring + * buffer is therefore minimized. + * + * O_RDONLY and O_RDWR are treated identically here. The tif_mode flag is + * checked in TIFFWriteCheck(). + * + * Create below fills in a blank creator signature and sets the file type + * to 'TIFF'. It is much better for the application to do this by Create'ing + * the file first and TIFFOpen'ing it later. + * --------- + * This code has been "Carbonized", and may not work with older MacOS versions. + * If so, grab the tif_apple.c out of an older libtiff distribution, like + * 3.5.5 from www.libtiff.org. + */ + +#include "tiffiop.h" +#include +#include +#include +#include + +#if defined(__PPCC__) || defined(__SC__) || defined(__MRC__) || defined(applec) +#define CtoPstr c2pstr +#endif + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (FSRead((short) fd, (long*) &size, (char*) buf) == noErr ? + size : (tsize_t) -1); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (FSWrite((short) fd, (long*) &size, (char*) buf) == noErr ? + size : (tsize_t) -1); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + long fpos, size; + + if (GetEOF((short) fd, &size) != noErr) + return EOF; + (void) GetFPos((short) fd, &fpos); + + switch (whence) { + case SEEK_CUR: + if (off + fpos > size) + SetEOF((short) fd, off + fpos); + if (SetFPos((short) fd, fsFromMark, off) != noErr) + return EOF; + break; + case SEEK_END: + if (off > 0) + SetEOF((short) fd, off + size); + if (SetFPos((short) fd, fsFromStart, off + size) != noErr) + return EOF; + break; + case SEEK_SET: + if (off > size) + SetEOF((short) fd, off); + if (SetFPos((short) fd, fsFromStart, off) != noErr) + return EOF; + break; + } + + return (toff_t)(GetFPos((short) fd, &fpos) == noErr ? fpos : EOF); +} + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (FSClose((short) fd)); +} + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + long size; + + if (GetEOF((short) fd, &size) != noErr) { + TIFFErrorExt(fd, "_tiffSizeProc", "%s: Cannot get file size"); + return (-1L); + } + return ((toff_t) size); +} + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +static void ourc2pstr( char* inString ) +{ + int sLen = strlen( inString ); + BlockMoveData( inString, &inString[1], sLen ); + inString[0] = sLen; +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + Str255 pname; + FInfo finfo; + short fref; + OSErr err; + FSSpec fSpec; + + strcpy((char*) pname, name); + ourc2pstr((char*) pname); + + err = FSMakeFSSpec( 0, 0, pname, &fSpec ); + + switch (_TIFFgetMode(mode, module)) { + default: + return ((TIFF*) 0); + case O_RDWR | O_CREAT | O_TRUNC: + if (FSpGetFInfo(&fSpec, &finfo) == noErr) + FSpDelete(&fSpec); + /* fall through */ + case O_RDWR | O_CREAT: + if ((err = FSpGetFInfo(&fSpec, &finfo)) == fnfErr) { + if (FSpCreate(&fSpec, ' ', 'TIFF', smSystemScript) != noErr) + goto badCreate; + if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr) + goto badOpen; + } else if (err == noErr) { + if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr) + goto badOpen; + } else + goto badOpen; + break; + case O_RDONLY: + if (FSpOpenDF(&fSpec, fsRdPerm, &fref) != noErr) + goto badOpen; + break; + case O_RDWR: + if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr) + goto badOpen; + break; + } + return (TIFFFdOpen((int) fref, name, mode)); +badCreate: + TIFFErrorExt(0, module, "%s: Cannot create", name); + return ((TIFF*) 0); +badOpen: + TIFFErrorExt(0, module, "%s: Cannot open", name); + return ((TIFF*) 0); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (NewPtr((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + DisposePtr(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + Ptr n = p; + + SetPtrSize(p, (size_t) s); + if (MemError() && (n = NewPtr((size_t) s)) != NULL) { + BlockMove(p, n, GetPtrSize(p)); + DisposePtr(p); + } + return ((tdata_t) n); +} + +static void +appleWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = appleWarningHandler; + +static void +appleErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = appleErrorHandler; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_aux.c b/thirdparty/libtiff/tif_aux.c new file mode 100644 index 00000000..272f0d9b --- /dev/null +++ b/thirdparty/libtiff/tif_aux.c @@ -0,0 +1,290 @@ +/* $Id: tif_aux.c,v 1.20.2.3 2010-06-09 21:15:27 bfriesen Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Auxiliary Support Routines. + */ +#include "tiffiop.h" +#include "tif_predict.h" +#include + +tdata_t +_TIFFCheckRealloc(TIFF* tif, tdata_t buffer, + size_t nmemb, size_t elem_size, const char* what) +{ + tdata_t cp = NULL; + tsize_t bytes = nmemb * elem_size; + + /* + * XXX: Check for integer overflow. + */ + if (nmemb && elem_size && bytes / elem_size == nmemb) + cp = _TIFFrealloc(buffer, bytes); + + if (cp == NULL) + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Failed to allocate memory for %s " + "(%ld elements of %ld bytes each)", + what,(long) nmemb, (long) elem_size); + + return cp; +} + +tdata_t +_TIFFCheckMalloc(TIFF* tif, size_t nmemb, size_t elem_size, const char* what) +{ + return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what); +} + +static int +TIFFDefaultTransferFunction(TIFFDirectory* td) +{ + uint16 **tf = td->td_transferfunction; + tsize_t i, n, nbytes; + + tf[0] = tf[1] = tf[2] = 0; + if (td->td_bitspersample >= sizeof(tsize_t) * 8 - 2) + return 0; + + n = 1<td_bitspersample; + nbytes = n * sizeof (uint16); + if (!(tf[0] = (uint16 *)_TIFFmalloc(nbytes))) + return 0; + tf[0][0] = 0; + for (i = 1; i < n; i++) { + double t = (double)i/((double) n-1.); + tf[0][i] = (uint16)floor(65535.*pow(t, 2.2) + .5); + } + + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + if (!(tf[1] = (uint16 *)_TIFFmalloc(nbytes))) + goto bad; + _TIFFmemcpy(tf[1], tf[0], nbytes); + if (!(tf[2] = (uint16 *)_TIFFmalloc(nbytes))) + goto bad; + _TIFFmemcpy(tf[2], tf[0], nbytes); + } + return 1; + +bad: + if (tf[0]) + _TIFFfree(tf[0]); + if (tf[1]) + _TIFFfree(tf[1]); + if (tf[2]) + _TIFFfree(tf[2]); + tf[0] = tf[1] = tf[2] = 0; + return 0; +} + +static int +TIFFDefaultRefBlackWhite(TIFFDirectory* td) +{ + int i; + + if (!(td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float)))) + return 0; + if (td->td_photometric == PHOTOMETRIC_YCBCR) { + /* + * YCbCr (Class Y) images must have the ReferenceBlackWhite + * tag set. Fix the broken images, which lacks that tag. + */ + td->td_refblackwhite[0] = 0.0F; + td->td_refblackwhite[1] = td->td_refblackwhite[3] = + td->td_refblackwhite[5] = 255.0F; + td->td_refblackwhite[2] = td->td_refblackwhite[4] = 128.0F; + } else { + /* + * Assume RGB (Class R) + */ + for (i = 0; i < 3; i++) { + td->td_refblackwhite[2*i+0] = 0; + td->td_refblackwhite[2*i+1] = + (float)((1L<td_bitspersample)-1L); + } + } + return 1; +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + * + * NB: We use the value in the directory, rather than + * explcit values so that defaults exist only one + * place in the library -- in TIFFDefaultDirectory. + */ +int +TIFFVGetFieldDefaulted(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (TIFFVGetField(tif, tag, ap)) + return (1); + switch (tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32 *) = td->td_subfiletype; + return (1); + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16 *) = td->td_bitspersample; + return (1); + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16 *) = td->td_threshholding; + return (1); + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16 *) = td->td_fillorder; + return (1); + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16 *) = td->td_orientation; + return (1); + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16 *) = td->td_samplesperpixel; + return (1); + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32 *) = td->td_rowsperstrip; + return (1); + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16 *) = td->td_minsamplevalue; + return (1); + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16 *) = td->td_maxsamplevalue; + return (1); + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16 *) = td->td_planarconfig; + return (1); + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16 *) = td->td_resolutionunit; + return (1); + case TIFFTAG_PREDICTOR: + { + TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data; + *va_arg(ap, uint16*) = (uint16) sp->predictor; + return 1; + } + case TIFFTAG_DOTRANGE: + *va_arg(ap, uint16 *) = 0; + *va_arg(ap, uint16 *) = (1<td_bitspersample)-1; + return (1); + case TIFFTAG_INKSET: + *va_arg(ap, uint16 *) = INKSET_CMYK; + return 1; + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16 *) = 4; + return (1); + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16 *) = td->td_extrasamples; + *va_arg(ap, uint16 **) = td->td_sampleinfo; + return (1); + case TIFFTAG_MATTEING: + *va_arg(ap, uint16 *) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + return (1); + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32 *) = td->td_tiledepth; + return (1); + case TIFFTAG_DATATYPE: + *va_arg(ap, uint16 *) = td->td_sampleformat-1; + return (1); + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16 *) = td->td_sampleformat; + return(1); + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32 *) = td->td_imagedepth; + return (1); + case TIFFTAG_YCBCRCOEFFICIENTS: + { + /* defaults are from CCIR Recommendation 601-1 */ + static float ycbcrcoeffs[] = { 0.299f, 0.587f, 0.114f }; + *va_arg(ap, float **) = ycbcrcoeffs; + return 1; + } + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[1]; + return (1); + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16 *) = td->td_ycbcrpositioning; + return (1); + case TIFFTAG_WHITEPOINT: + { + static float whitepoint[2]; + + /* TIFF 6.0 specification tells that it is no default + value for the WhitePoint, but AdobePhotoshop TIFF + Technical Note tells that it should be CIE D50. */ + whitepoint[0] = D50_X0 / (D50_X0 + D50_Y0 + D50_Z0); + whitepoint[1] = D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0); + *va_arg(ap, float **) = whitepoint; + return 1; + } + case TIFFTAG_TRANSFERFUNCTION: + if (!td->td_transferfunction[0] && + !TIFFDefaultTransferFunction(td)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space for \"TransferFunction\" tag"); + return (0); + } + *va_arg(ap, uint16 **) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, uint16 **) = td->td_transferfunction[1]; + *va_arg(ap, uint16 **) = td->td_transferfunction[2]; + } + return (1); + case TIFFTAG_REFERENCEBLACKWHITE: + if (!td->td_refblackwhite && !TIFFDefaultRefBlackWhite(td)) + return (0); + *va_arg(ap, float **) = td->td_refblackwhite; + return (1); + } + return 0; +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + */ +int +TIFFGetFieldDefaulted(TIFF* tif, ttag_t tag, ...) +{ + int ok; + va_list ap; + + va_start(ap, tag); + ok = TIFFVGetFieldDefaulted(tif, tag, ap); + va_end(ap); + return (ok); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_close.c b/thirdparty/libtiff/tif_close.c new file mode 100644 index 00000000..02591ba9 --- /dev/null +++ b/thirdparty/libtiff/tif_close.c @@ -0,0 +1,126 @@ +/* $Id: tif_close.c,v 1.10.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +/************************************************************************/ +/* TIFFCleanup() */ +/************************************************************************/ + +/** + * Auxiliary function to free the TIFF structure. Given structure will be + * completetly freed, so you should save opened file handle and pointer + * to the close procedure in external variables before calling + * _TIFFCleanup(), if you will need these ones to close the file. + * + * @param tif A TIFF pointer. + */ + +void +TIFFCleanup(TIFF* tif) +{ + if (tif->tif_mode != O_RDONLY) + /* + * Flush buffered data and directory (if dirty). + */ + TIFFFlush(tif); + (*tif->tif_cleanup)(tif); + TIFFFreeDirectory(tif); + + if (tif->tif_dirlist) + _TIFFfree(tif->tif_dirlist); + + /* Clean up client info links */ + while( tif->tif_clientinfo ) + { + TIFFClientInfoLink *link = tif->tif_clientinfo; + + tif->tif_clientinfo = link->next; + _TIFFfree( link->name ); + _TIFFfree( link ); + } + + if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) + _TIFFfree(tif->tif_rawdata); + if (isMapped(tif)) + TIFFUnmapFileContents(tif, tif->tif_base, tif->tif_size); + + /* Clean up custom fields */ + if (tif->tif_nfields > 0) + { + size_t i; + + for (i = 0; i < tif->tif_nfields; i++) + { + TIFFFieldInfo *fld = tif->tif_fieldinfo[i]; + if (fld->field_bit == FIELD_CUSTOM && + strncmp("Tag ", fld->field_name, 4) == 0) + { + _TIFFfree(fld->field_name); + _TIFFfree(fld); + } + } + + _TIFFfree(tif->tif_fieldinfo); + } + + _TIFFfree(tif); +} + +/************************************************************************/ +/* TIFFClose() */ +/************************************************************************/ + +/** + * Close a previously opened TIFF file. + * + * TIFFClose closes a file that was previously opened with TIFFOpen(). + * Any buffered data are flushed to the file, including the contents of + * the current directory (if modified); and all resources are reclaimed. + * + * @param tif A TIFF pointer. + */ + +void +TIFFClose(TIFF* tif) +{ + TIFFCloseProc closeproc = tif->tif_closeproc; + thandle_t fd = tif->tif_clientdata; + + TIFFCleanup(tif); + (void) (*closeproc)(fd); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_codec.c b/thirdparty/libtiff/tif_codec.c new file mode 100644 index 00000000..d5c6fd11 --- /dev/null +++ b/thirdparty/libtiff/tif_codec.c @@ -0,0 +1,160 @@ +/* $Id: tif_codec.c,v 1.10.2.2 2010-06-08 18:50:41 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Builtin Compression Scheme Configuration Support. + */ +#include "tiffiop.h" + +static int NotConfigured(TIFF*, int); + +#ifndef LZW_SUPPORT +#define TIFFInitLZW NotConfigured +#endif +#ifndef PACKBITS_SUPPORT +#define TIFFInitPackBits NotConfigured +#endif +#ifndef THUNDER_SUPPORT +#define TIFFInitThunderScan NotConfigured +#endif +#ifndef NEXT_SUPPORT +#define TIFFInitNeXT NotConfigured +#endif +#ifndef JPEG_SUPPORT +#define TIFFInitJPEG NotConfigured +#endif +#ifndef OJPEG_SUPPORT +#define TIFFInitOJPEG NotConfigured +#endif +#ifndef CCITT_SUPPORT +#define TIFFInitCCITTRLE NotConfigured +#define TIFFInitCCITTRLEW NotConfigured +#define TIFFInitCCITTFax3 NotConfigured +#define TIFFInitCCITTFax4 NotConfigured +#endif +#ifndef JBIG_SUPPORT +#define TIFFInitJBIG NotConfigured +#endif +#ifndef ZIP_SUPPORT +#define TIFFInitZIP NotConfigured +#endif +#ifndef PIXARLOG_SUPPORT +#define TIFFInitPixarLog NotConfigured +#endif +#ifndef LOGLUV_SUPPORT +#define TIFFInitSGILog NotConfigured +#endif + +/* + * Compression schemes statically built into the library. + */ +#ifdef VMS +const TIFFCodec _TIFFBuiltinCODECS[] = { +#else +TIFFCodec _TIFFBuiltinCODECS[] = { +#endif + { "None", COMPRESSION_NONE, TIFFInitDumpMode }, + { "LZW", COMPRESSION_LZW, TIFFInitLZW }, + { "PackBits", COMPRESSION_PACKBITS, TIFFInitPackBits }, + { "ThunderScan", COMPRESSION_THUNDERSCAN,TIFFInitThunderScan }, + { "NeXT", COMPRESSION_NEXT, TIFFInitNeXT }, + { "JPEG", COMPRESSION_JPEG, TIFFInitJPEG }, + { "Old-style JPEG", COMPRESSION_OJPEG, TIFFInitOJPEG }, + { "CCITT RLE", COMPRESSION_CCITTRLE, TIFFInitCCITTRLE }, + { "CCITT RLE/W", COMPRESSION_CCITTRLEW, TIFFInitCCITTRLEW }, + { "CCITT Group 3", COMPRESSION_CCITTFAX3, TIFFInitCCITTFax3 }, + { "CCITT Group 4", COMPRESSION_CCITTFAX4, TIFFInitCCITTFax4 }, + { "ISO JBIG", COMPRESSION_JBIG, TIFFInitJBIG }, + { "Deflate", COMPRESSION_DEFLATE, TIFFInitZIP }, + { "AdobeDeflate", COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP }, + { "PixarLog", COMPRESSION_PIXARLOG, TIFFInitPixarLog }, + { "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog }, + { "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog }, + { NULL, 0, NULL } +}; + +static int +_notConfigured(TIFF* tif) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + char compression_code[20]; + + sprintf( compression_code, "%d", tif->tif_dir.td_compression ); + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s compression support is not configured", + c ? c->name : compression_code ); + return (0); +} + +static int +NotConfigured(TIFF* tif, int scheme) +{ + (void) scheme; + + tif->tif_decodestatus = FALSE; + tif->tif_setupdecode = _notConfigured; + tif->tif_encodestatus = FALSE; + tif->tif_setupencode = _notConfigured; + return (1); +} + +/************************************************************************/ +/* TIFFIsCODECConfigured() */ +/************************************************************************/ + +/** + * Check whether we have working codec for the specific coding scheme. + * + * @return returns 1 if the codec is configured and working. Otherwise + * 0 will be returned. + */ + +int +TIFFIsCODECConfigured(uint16 scheme) +{ + const TIFFCodec* codec = TIFFFindCODEC(scheme); + + if(codec == NULL) { + return 0; + } + if(codec->init == NULL) { + return 0; + } + if(codec->init != NotConfigured){ + return 1; + } + return 0; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_color.c b/thirdparty/libtiff/tif_color.c new file mode 100644 index 00000000..02eb346b --- /dev/null +++ b/thirdparty/libtiff/tif_color.c @@ -0,0 +1,282 @@ +/* $Id: tif_color.c,v 1.12.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken + * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with + * the permission of John Cupitt, the VIPS author. + */ + +/* + * TIFF Library. + * + * Color space conversion routines. + */ + +#include "tiffiop.h" +#include + +/* + * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ. + */ +void +TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b, + float *X, float *Y, float *Z) +{ + float L = (float)l * 100.0F / 255.0F; + float cby, tmp; + + if( L < 8.856F ) { + *Y = (L * cielab->Y0) / 903.292F; + cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F; + } else { + cby = (L + 16.0F) / 116.0F; + *Y = cielab->Y0 * cby * cby * cby; + } + + tmp = (float)a / 500.0F + cby; + if( tmp < 0.2069F ) + *X = cielab->X0 * (tmp - 0.13793F) / 7.787F; + else + *X = cielab->X0 * tmp * tmp * tmp; + + tmp = cby - (float)b / 200.0F; + if( tmp < 0.2069F ) + *Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F; + else + *Z = cielab->Z0 * tmp * tmp * tmp; +} + +#define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5))) +/* + * Convert color value from the XYZ space to RGB. + */ +void +TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z, + uint32 *r, uint32 *g, uint32 *b) +{ + int i; + float Yr, Yg, Yb; + float *matrix = &cielab->display.d_mat[0][0]; + + /* Multiply through the matrix to get luminosity values. */ + Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z; + Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z; + Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z; + + /* Clip input */ + Yr = TIFFmax(Yr, cielab->display.d_Y0R); + Yg = TIFFmax(Yg, cielab->display.d_Y0G); + Yb = TIFFmax(Yb, cielab->display.d_Y0B); + + /* Avoid overflow in case of wrong input values */ + Yr = TIFFmin(Yr, cielab->display.d_YCR); + Yg = TIFFmin(Yg, cielab->display.d_YCG); + Yb = TIFFmin(Yb, cielab->display.d_YCB); + + /* Turn luminosity to colour value. */ + i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep); + i = TIFFmin(cielab->range, i); + *r = RINT(cielab->Yr2r[i]); + + i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep); + i = TIFFmin(cielab->range, i); + *g = RINT(cielab->Yg2g[i]); + + i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep); + i = TIFFmin(cielab->range, i); + *b = RINT(cielab->Yb2b[i]); + + /* Clip output. */ + *r = TIFFmin(*r, cielab->display.d_Vrwr); + *g = TIFFmin(*g, cielab->display.d_Vrwg); + *b = TIFFmin(*b, cielab->display.d_Vrwb); +} +#undef RINT + +/* + * Allocate conversion state structures and make look_up tables for + * the Yr,Yb,Yg <=> r,g,b conversions. + */ +int +TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab, + TIFFDisplay *display, float *refWhite) +{ + int i; + double gamma; + + cielab->range = CIELABTORGB_TABLE_RANGE; + + _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay)); + + /* Red */ + gamma = 1.0 / cielab->display.d_gammaR ; + cielab->rstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for(i = 0; i <= cielab->range; i++) { + cielab->Yr2r[i] = cielab->display.d_Vrwr + * ((float)pow((double)i / cielab->range, gamma)); + } + + /* Green */ + gamma = 1.0 / cielab->display.d_gammaG ; + cielab->gstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for(i = 0; i <= cielab->range; i++) { + cielab->Yg2g[i] = cielab->display.d_Vrwg + * ((float)pow((double)i / cielab->range, gamma)); + } + + /* Blue */ + gamma = 1.0 / cielab->display.d_gammaB ; + cielab->bstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for(i = 0; i <= cielab->range; i++) { + cielab->Yb2b[i] = cielab->display.d_Vrwb + * ((float)pow((double)i / cielab->range, gamma)); + } + + /* Init reference white point */ + cielab->X0 = refWhite[0]; + cielab->Y0 = refWhite[1]; + cielab->Z0 = refWhite[2]; + + return 0; +} + +/* + * Convert color value from the YCbCr space to CIE XYZ. + * The colorspace conversion algorithm comes from the IJG v5a code; + * see below for more information on how it works. + */ +#define SHIFT 16 +#define FIX(x) ((int32)((x) * (1L<(max)?(max):(f)) +#define HICLAMP(f,max) ((f)>(max)?(max):(f)) + +void +TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr, + uint32 *r, uint32 *g, uint32 *b) +{ + /* XXX: Only 8-bit YCbCr input supported for now */ + Y = HICLAMP(Y, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255); + + *r = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]]; + *g = ycbcr->clamptab[ycbcr->Y_tab[Y] + + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT)]; + *b = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]]; +} + +/* + * Initialize the YCbCr->RGB conversion tables. The conversion + * is done according to the 6.0 spec: + * + * R = Y + Cr*(2 - 2*LumaRed) + * B = Y + Cb*(2 - 2*LumaBlue) + * G = Y + * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen + * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen + * + * To avoid floating point arithmetic the fractional constants that + * come out of the equations are represented as fixed point values + * in the range 0...2^16. We also eliminate multiplications by + * pre-calculating possible values indexed by Cb and Cr (this code + * assumes conversion is being done for 8-bit samples). + */ +int +TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite) +{ + TIFFRGBValue* clamptab; + int i; + +#define LumaRed luma[0] +#define LumaGreen luma[1] +#define LumaBlue luma[2] + + clamptab = (TIFFRGBValue*)( + (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long))); + _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */ + ycbcr->clamptab = (clamptab += 256); + for (i = 0; i < 256; i++) + clamptab[i] = (TIFFRGBValue) i; + _TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */ + ycbcr->Cr_r_tab = (int*) (clamptab + 3*256); + ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256; + ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256); + ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256; + ycbcr->Y_tab = ycbcr->Cb_g_tab + 256; + + { float f1 = 2-2*LumaRed; int32 D1 = FIX(f1); + float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2); + float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3); + float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4); + int x; + +#undef LumaBlue +#undef LumaGreen +#undef LumaRed + + /* + * i is the actual input pixel value in the range 0..255 + * Cb and Cr values are in the range -128..127 (actually + * they are in a range defined by the ReferenceBlackWhite + * tag) so there is some range shifting to do here when + * constructing tables indexed by the raw pixel data. + */ + for (i = 0, x = -128; i < 256; i++, x++) { + int32 Cr = (int32)Code2V(x, refBlackWhite[4] - 128.0F, + refBlackWhite[5] - 128.0F, 127); + int32 Cb = (int32)Code2V(x, refBlackWhite[2] - 128.0F, + refBlackWhite[3] - 128.0F, 127); + + ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT); + ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT); + ycbcr->Cr_g_tab[i] = D2*Cr; + ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF; + ycbcr->Y_tab[i] = + (int32)Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255); + } + } + + return 0; +} +#undef HICLAMP +#undef CLAMP +#undef Code2V +#undef SHIFT +#undef ONE_HALF +#undef FIX + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_compress.c b/thirdparty/libtiff/tif_compress.c new file mode 100644 index 00000000..0ce509b0 --- /dev/null +++ b/thirdparty/libtiff/tif_compress.c @@ -0,0 +1,295 @@ +/* $Id: tif_compress.c,v 1.13.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Compression Scheme Configuration Support. + */ +#include "tiffiop.h" + +static int +TIFFNoEncode(TIFF* tif, const char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s %s encoding is not implemented", + c->name, method); + } else { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme %u %s encoding is not implemented", + tif->tif_dir.td_compression, method); + } + return (-1); +} + +int +_TIFFNoRowEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "scanline")); +} + +int +_TIFFNoStripEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "strip")); +} + +int +_TIFFNoTileEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "tile")); +} + +static int +TIFFNoDecode(TIFF* tif, const char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s %s decoding is not implemented", + c->name, method); + else + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme %u %s decoding is not implemented", + tif->tif_dir.td_compression, method); + return (-1); +} + +int +_TIFFNoRowDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "scanline")); +} + +int +_TIFFNoStripDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "strip")); +} + +int +_TIFFNoTileDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "tile")); +} + +int +_TIFFNoSeek(TIFF* tif, uint32 off) +{ + (void) off; + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression algorithm does not support random access"); + return (0); +} + +int +_TIFFNoPreCode(TIFF* tif, tsample_t s) +{ + (void) tif; (void) s; + return (1); +} + +static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); } +static void _TIFFvoid(TIFF* tif) { (void) tif; } + +void +_TIFFSetDefaultCompressionState(TIFF* tif) +{ + tif->tif_decodestatus = TRUE; + tif->tif_setupdecode = _TIFFtrue; + tif->tif_predecode = _TIFFNoPreCode; + tif->tif_decoderow = _TIFFNoRowDecode; + tif->tif_decodestrip = _TIFFNoStripDecode; + tif->tif_decodetile = _TIFFNoTileDecode; + tif->tif_encodestatus = TRUE; + tif->tif_setupencode = _TIFFtrue; + tif->tif_preencode = _TIFFNoPreCode; + tif->tif_postencode = _TIFFtrue; + tif->tif_encoderow = _TIFFNoRowEncode; + tif->tif_encodestrip = _TIFFNoStripEncode; + tif->tif_encodetile = _TIFFNoTileEncode; + tif->tif_close = _TIFFvoid; + tif->tif_seek = _TIFFNoSeek; + tif->tif_cleanup = _TIFFvoid; + tif->tif_defstripsize = _TIFFDefaultStripSize; + tif->tif_deftilesize = _TIFFDefaultTileSize; + tif->tif_flags &= ~(TIFF_NOBITREV|TIFF_NOREADRAW); +} + +int +TIFFSetCompressionScheme(TIFF* tif, int scheme) +{ + const TIFFCodec *c = TIFFFindCODEC((uint16) scheme); + + _TIFFSetDefaultCompressionState(tif); + /* + * Don't treat an unknown compression scheme as an error. + * This permits applications to open files with data that + * the library does not have builtin support for, but which + * may still be meaningful. + */ + return (c ? (*c->init)(tif, scheme) : 1); +} + +/* + * Other compression schemes may be registered. Registered + * schemes can also override the builtin versions provided + * by this library. + */ +typedef struct _codec { + struct _codec* next; + TIFFCodec* info; +} codec_t; +static codec_t* registeredCODECS = NULL; + +const TIFFCodec* +TIFFFindCODEC(uint16 scheme) +{ + const TIFFCodec* c; + codec_t* cd; + + for (cd = registeredCODECS; cd; cd = cd->next) + if (cd->info->scheme == scheme) + return ((const TIFFCodec*) cd->info); + for (c = _TIFFBuiltinCODECS; c->name; c++) + if (c->scheme == scheme) + return (c); + return ((const TIFFCodec*) 0); +} + +TIFFCodec* +TIFFRegisterCODEC(uint16 scheme, const char* name, TIFFInitMethod init) +{ + codec_t* cd = (codec_t*) + _TIFFmalloc(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1); + + if (cd != NULL) { + cd->info = (TIFFCodec*) ((tidata_t) cd + sizeof (codec_t)); + cd->info->name = (char*) + ((tidata_t) cd->info + sizeof (TIFFCodec)); + strcpy(cd->info->name, name); + cd->info->scheme = scheme; + cd->info->init = init; + cd->next = registeredCODECS; + registeredCODECS = cd; + } else { + TIFFErrorExt(0, "TIFFRegisterCODEC", + "No space to register compression scheme %s", name); + return NULL; + } + return (cd->info); +} + +void +TIFFUnRegisterCODEC(TIFFCodec* c) +{ + codec_t* cd; + codec_t** pcd; + + for (pcd = ®isteredCODECS; (cd = *pcd); pcd = &cd->next) + if (cd->info == c) { + *pcd = cd->next; + _TIFFfree(cd); + return; + } + TIFFErrorExt(0, "TIFFUnRegisterCODEC", + "Cannot remove compression scheme %s; not registered", c->name); +} + +/************************************************************************/ +/* TIFFGetConfisuredCODECs() */ +/************************************************************************/ + +/** + * Get list of configured codecs, both built-in and registered by user. + * Caller is responsible to free this structure. + * + * @return returns array of TIFFCodec records (the last record should be NULL) + * or NULL if function failed. + */ + +TIFFCodec* +TIFFGetConfiguredCODECs() +{ + int i = 1; + codec_t *cd; + const TIFFCodec *c; + TIFFCodec *codecs = NULL, *new_codecs; + + for (cd = registeredCODECS; cd; cd = cd->next) { + new_codecs = (TIFFCodec *) + _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, cd, sizeof(TIFFCodec)); + i++; + } + for (c = _TIFFBuiltinCODECS; c->name; c++) { + if (TIFFIsCODECConfigured(c->scheme)) { + new_codecs = (TIFFCodec *) + _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, (const tdata_t)c, sizeof(TIFFCodec)); + i++; + } + } + + new_codecs = (TIFFCodec *) _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemset(codecs + i - 1, 0, sizeof(TIFFCodec)); + + return codecs; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_config.h b/thirdparty/libtiff/tif_config.h new file mode 100644 index 00000000..08d1f0d0 --- /dev/null +++ b/thirdparty/libtiff/tif_config.h @@ -0,0 +1,70 @@ +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define as 0 or 1 according to the floating point format suported by the + machine */ +#define HAVE_IEEEFP 1 + +/* Define to 1 if you have the `jbg_newlen' function. */ +#define HAVE_JBG_NEWLEN 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SEARCH_H 1 + +/* Define to 1 if you have the `setmode' function. */ +#define HAVE_SETMODE 1 + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + + +#ifdef _MSC_VER +/* Signed 64-bit type */ +#define TIFF_INT64_T signed __int64 +/* Unsigned 64-bit type */ +#define TIFF_UINT64_T unsigned __int64 +#else +/* Signed 64-bit type */ +#define TIFF_INT64_T long long +/* Signed 64-bit type */ +#define TIFF_UINT64_T unsigned long long +#endif + +/* Set the native cpu bit order */ +#define HOST_FILLORDER FILLORDER_LSB2MSB + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +# ifndef inline +# define inline __inline +# endif +#endif + +#define lfind _lfind +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_dir.c b/thirdparty/libtiff/tif_dir.c new file mode 100644 index 00000000..ac44b381 --- /dev/null +++ b/thirdparty/libtiff/tif_dir.c @@ -0,0 +1,1389 @@ +/* $Id: tif_dir.c,v 1.75.2.5 2010-06-09 21:15:27 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Tag Get & Set Routines. + * (and also some miscellaneous stuff) + */ +#include "tiffiop.h" + +/* + * These are used in the backwards compatibility code... + */ +#define DATATYPE_VOID 0 /* !untyped data */ +#define DATATYPE_INT 1 /* !signed integer data */ +#define DATATYPE_UINT 2 /* !unsigned integer data */ +#define DATATYPE_IEEEFP 3 /* !IEEE floating point data */ + +static void +setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size) +{ + if (*vpp) + _TIFFfree(*vpp), *vpp = 0; + if (vp) { + tsize_t bytes = nmemb * elem_size; + if (elem_size && bytes / elem_size == nmemb) + *vpp = (void*) _TIFFmalloc(bytes); + if (*vpp) + _TIFFmemcpy(*vpp, vp, bytes); + } +} +void _TIFFsetByteArray(void** vpp, void* vp, uint32 n) + { setByteArray(vpp, vp, n, 1); } +void _TIFFsetString(char** cpp, char* cp) + { setByteArray((void**) cpp, (void*) cp, strlen(cp)+1, 1); } +void _TIFFsetNString(char** cpp, char* cp, uint32 n) + { setByteArray((void**) cpp, (void*) cp, n, 1); } +void _TIFFsetShortArray(uint16** wpp, uint16* wp, uint32 n) + { setByteArray((void**) wpp, (void*) wp, n, sizeof (uint16)); } +void _TIFFsetLongArray(uint32** lpp, uint32* lp, uint32 n) + { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint32)); } +void _TIFFsetFloatArray(float** fpp, float* fp, uint32 n) + { setByteArray((void**) fpp, (void*) fp, n, sizeof (float)); } +void _TIFFsetDoubleArray(double** dpp, double* dp, uint32 n) + { setByteArray((void**) dpp, (void*) dp, n, sizeof (double)); } + +/* + * Install extra samples information. + */ +static int +setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v) +{ +/* XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below */ +#define EXTRASAMPLE_COREL_UNASSALPHA 999 + + uint16* va; + uint32 i; + + *v = va_arg(ap, uint32); + if ((uint16) *v > td->td_samplesperpixel) + return 0; + va = va_arg(ap, uint16*); + if (*v > 0 && va == NULL) /* typically missing param */ + return 0; + for (i = 0; i < *v; i++) { + if (va[i] > EXTRASAMPLE_UNASSALPHA) { + /* + * XXX: Corel Draw is known to produce incorrect + * ExtraSamples tags which must be patched here if we + * want to be able to open some of the damaged TIFF + * files: + */ + if (va[i] == EXTRASAMPLE_COREL_UNASSALPHA) + va[i] = EXTRASAMPLE_UNASSALPHA; + else + return 0; + } + } + td->td_extrasamples = (uint16) *v; + _TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples); + return 1; + +#undef EXTRASAMPLE_COREL_UNASSALPHA +} + +static uint32 +checkInkNamesString(TIFF* tif, uint32 slen, const char* s) +{ + TIFFDirectory* td = &tif->tif_dir; + uint16 i = td->td_samplesperpixel; + + if (slen > 0) { + const char* ep = s+slen; + const char* cp = s; + for (; i > 0; i--) { + for (; *cp != '\0'; cp++) + if (cp >= ep) + goto bad; + cp++; /* skip \0 */ + } + return (cp-s); + } +bad: + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", + "%s: Invalid InkNames value; expecting %d names, found %d", + tif->tif_name, + td->td_samplesperpixel, + td->td_samplesperpixel-i); + return (0); +} + +static int +_TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + static const char module[] = "_TIFFVSetField"; + + TIFFDirectory* td = &tif->tif_dir; + int status = 1; + uint32 v32, i, v; + char* s; + + switch (tag) { + case TIFFTAG_SUBFILETYPE: + td->td_subfiletype = va_arg(ap, uint32); + break; + case TIFFTAG_IMAGEWIDTH: + td->td_imagewidth = va_arg(ap, uint32); + break; + case TIFFTAG_IMAGELENGTH: + td->td_imagelength = va_arg(ap, uint32); + break; + case TIFFTAG_BITSPERSAMPLE: + td->td_bitspersample = (uint16) va_arg(ap, int); + /* + * If the data require post-decoding processing to byte-swap + * samples, set it up here. Note that since tags are required + * to be ordered, compression code can override this behaviour + * in the setup method if it wants to roll the post decoding + * work in with its normal work. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (td->td_bitspersample == 16) + tif->tif_postdecode = _TIFFSwab16BitData; + else if (td->td_bitspersample == 24) + tif->tif_postdecode = _TIFFSwab24BitData; + else if (td->td_bitspersample == 32) + tif->tif_postdecode = _TIFFSwab32BitData; + else if (td->td_bitspersample == 64) + tif->tif_postdecode = _TIFFSwab64BitData; + else if (td->td_bitspersample == 128) /* two 64's */ + tif->tif_postdecode = _TIFFSwab64BitData; + } + break; + case TIFFTAG_COMPRESSION: + v = va_arg(ap, uint32) & 0xffff; + /* + * If we're changing the compression scheme, the notify the + * previous module so that it can cleanup any state it's + * setup. + */ + if (TIFFFieldSet(tif, FIELD_COMPRESSION)) { + if (td->td_compression == v) + break; + (*tif->tif_cleanup)(tif); + tif->tif_flags &= ~TIFF_CODERSETUP; + } + /* + * Setup new compression routine state. + */ + if( (status = TIFFSetCompressionScheme(tif, v)) != 0 ) + td->td_compression = (uint16) v; + else + status = 0; + break; + case TIFFTAG_PHOTOMETRIC: + td->td_photometric = (uint16) va_arg(ap, int); + break; + case TIFFTAG_THRESHHOLDING: + td->td_threshholding = (uint16) va_arg(ap, int); + break; + case TIFFTAG_FILLORDER: + v = va_arg(ap, uint32); + if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB) + goto badvalue; + td->td_fillorder = (uint16) v; + break; + case TIFFTAG_ORIENTATION: + v = va_arg(ap, uint32); + if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v) + goto badvalue; + else + td->td_orientation = (uint16) v; + break; + case TIFFTAG_SAMPLESPERPIXEL: + /* XXX should cross check -- e.g. if pallette, then 1 */ + v = va_arg(ap, uint32); + if (v == 0) + goto badvalue; + td->td_samplesperpixel = (uint16) v; + break; + case TIFFTAG_ROWSPERSTRIP: + v32 = va_arg(ap, uint32); + if (v32 == 0) + goto badvalue32; + td->td_rowsperstrip = v32; + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + td->td_tilelength = v32; + td->td_tilewidth = td->td_imagewidth; + } + break; + case TIFFTAG_MINSAMPLEVALUE: + td->td_minsamplevalue = (uint16) va_arg(ap, int); + break; + case TIFFTAG_MAXSAMPLEVALUE: + td->td_maxsamplevalue = (uint16) va_arg(ap, int); + break; + case TIFFTAG_SMINSAMPLEVALUE: + td->td_sminsamplevalue = va_arg(ap, double); + break; + case TIFFTAG_SMAXSAMPLEVALUE: + td->td_smaxsamplevalue = va_arg(ap, double); + break; + case TIFFTAG_XRESOLUTION: + td->td_xresolution = (float) va_arg(ap, double); + break; + case TIFFTAG_YRESOLUTION: + td->td_yresolution = (float) va_arg(ap, double); + break; + case TIFFTAG_PLANARCONFIG: + v = va_arg(ap, uint32); + if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) + goto badvalue; + td->td_planarconfig = (uint16) v; + break; + case TIFFTAG_XPOSITION: + td->td_xposition = (float) va_arg(ap, double); + break; + case TIFFTAG_YPOSITION: + td->td_yposition = (float) va_arg(ap, double); + break; + case TIFFTAG_RESOLUTIONUNIT: + v = va_arg(ap, uint32); + if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v) + goto badvalue; + td->td_resolutionunit = (uint16) v; + break; + case TIFFTAG_PAGENUMBER: + td->td_pagenumber[0] = (uint16) va_arg(ap, int); + td->td_pagenumber[1] = (uint16) va_arg(ap, int); + break; + case TIFFTAG_HALFTONEHINTS: + td->td_halftonehints[0] = (uint16) va_arg(ap, int); + td->td_halftonehints[1] = (uint16) va_arg(ap, int); + break; + case TIFFTAG_COLORMAP: + v32 = (uint32)(1L<td_bitspersample); + _TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32); + _TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32); + _TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32); + break; + case TIFFTAG_EXTRASAMPLES: + if (!setExtraSamples(td, ap, &v)) + goto badvalue; + break; + case TIFFTAG_MATTEING: + td->td_extrasamples = (uint16) (va_arg(ap, int) != 0); + if (td->td_extrasamples) { + uint16 sv = EXTRASAMPLE_ASSOCALPHA; + _TIFFsetShortArray(&td->td_sampleinfo, &sv, 1); + } + break; + case TIFFTAG_TILEWIDTH: + v32 = va_arg(ap, uint32); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Nonstandard tile width %d, convert file", v32); + } + td->td_tilewidth = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILELENGTH: + v32 = va_arg(ap, uint32); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Nonstandard tile length %d, convert file", v32); + } + td->td_tilelength = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILEDEPTH: + v32 = va_arg(ap, uint32); + if (v32 == 0) + goto badvalue32; + td->td_tiledepth = v32; + break; + case TIFFTAG_DATATYPE: + v = va_arg(ap, uint32); + switch (v) { + case DATATYPE_VOID: v = SAMPLEFORMAT_VOID; break; + case DATATYPE_INT: v = SAMPLEFORMAT_INT; break; + case DATATYPE_UINT: v = SAMPLEFORMAT_UINT; break; + case DATATYPE_IEEEFP: v = SAMPLEFORMAT_IEEEFP;break; + default: goto badvalue; + } + td->td_sampleformat = (uint16) v; + break; + case TIFFTAG_SAMPLEFORMAT: + v = va_arg(ap, uint32); + if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v) + goto badvalue; + td->td_sampleformat = (uint16) v; + + /* Try to fix up the SWAB function for complex data. */ + if( td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT + && td->td_bitspersample == 32 + && tif->tif_postdecode == _TIFFSwab32BitData ) + tif->tif_postdecode = _TIFFSwab16BitData; + else if( (td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT + || td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP) + && td->td_bitspersample == 64 + && tif->tif_postdecode == _TIFFSwab64BitData ) + tif->tif_postdecode = _TIFFSwab32BitData; + break; + case TIFFTAG_IMAGEDEPTH: + td->td_imagedepth = va_arg(ap, uint32); + break; + case TIFFTAG_SUBIFD: + if ((tif->tif_flags & TIFF_INSUBIFD) == 0) { + td->td_nsubifd = (uint16) va_arg(ap, int); + _TIFFsetLongArray(&td->td_subifd, va_arg(ap, uint32*), + (long) td->td_nsubifd); + } else { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Sorry, cannot nest SubIFDs", + tif->tif_name); + status = 0; + } + break; + case TIFFTAG_YCBCRPOSITIONING: + td->td_ycbcrpositioning = (uint16) va_arg(ap, int); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, int); + td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, int); + break; + case TIFFTAG_TRANSFERFUNCTION: + v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1; + for (i = 0; i < v; i++) + _TIFFsetShortArray(&td->td_transferfunction[i], + va_arg(ap, uint16*), 1L<td_bitspersample); + break; + case TIFFTAG_REFERENCEBLACKWHITE: + /* XXX should check for null range */ + _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6); + break; + case TIFFTAG_INKNAMES: + v = va_arg(ap, uint32); + s = va_arg(ap, char*); + v = checkInkNamesString(tif, v, s); + status = v > 0; + if( v > 0 ) { + _TIFFsetNString(&td->td_inknames, s, v); + td->td_inknameslen = v; + } + break; + default: { + TIFFTagValue *tv; + int tv_size, iCustom; + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + + /* + * This can happen if multiple images are open with different + * codecs which have private tags. The global tag information + * table may then have tags that are valid for one file but not + * the other. If the client tries to set a tag that is not valid + * for the image's codec then we'll arrive here. This + * happens, for example, when tiffcp is used to convert between + * compression schemes and codec-specific tags are blindly copied. + */ + if(fip == NULL || fip->field_bit != FIELD_CUSTOM) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Invalid %stag \"%s\" (not supported by codec)", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", + fip ? fip->field_name : "Unknown"); + status = 0; + break; + } + + /* + * Find the existing entry for this custom value. + */ + tv = NULL; + for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++) { + if (td->td_customValues[iCustom].info->field_tag == tag) { + tv = td->td_customValues + iCustom; + if (tv->value != NULL) { + _TIFFfree(tv->value); + tv->value = NULL; + } + break; + } + } + + /* + * Grow the custom list if the entry was not found. + */ + if(tv == NULL) { + TIFFTagValue *new_customValues; + + td->td_customValueCount++; + new_customValues = (TIFFTagValue *) + _TIFFrealloc(td->td_customValues, + sizeof(TIFFTagValue) * td->td_customValueCount); + if (!new_customValues) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Failed to allocate space for list of custom values", + tif->tif_name); + status = 0; + goto end; + } + + td->td_customValues = new_customValues; + + tv = td->td_customValues + (td->td_customValueCount - 1); + tv->info = fip; + tv->value = NULL; + tv->count = 0; + } + + /* + * Set custom value ... save a copy of the custom tag value. + */ + tv_size = _TIFFDataSize(fip->field_type); + if (tv_size == 0) { + status = 0; + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad field type %d for \"%s\"", + tif->tif_name, fip->field_type, + fip->field_name); + goto end; + } + + if(fip->field_passcount) { + if (fip->field_writecount == TIFF_VARIABLE2) + tv->count = (uint32) va_arg(ap, uint32); + else + tv->count = (int) va_arg(ap, int); + } else if (fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2) + tv->count = 1; + else if (fip->field_writecount == TIFF_SPP) + tv->count = td->td_samplesperpixel; + else + tv->count = fip->field_writecount; + + + if (fip->field_type == TIFF_ASCII) + _TIFFsetString((char **)&tv->value, va_arg(ap, char *)); + else { + tv->value = _TIFFCheckMalloc(tif, tv_size, tv->count, + "Tag Value"); + if (!tv->value) { + status = 0; + goto end; + } + + if ((fip->field_passcount + || fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2 + || fip->field_writecount == TIFF_SPP + || tv->count > 1) + && fip->field_tag != TIFFTAG_PAGENUMBER + && fip->field_tag != TIFFTAG_HALFTONEHINTS + && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING + && fip->field_tag != TIFFTAG_DOTRANGE) { + _TIFFmemcpy(tv->value, va_arg(ap, void *), + tv->count * tv_size); + } else { + /* + * XXX: The following loop required to handle + * TIFFTAG_PAGENUMBER, TIFFTAG_HALFTONEHINTS, + * TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE tags. + * These tags are actually arrays and should be passed as + * array pointers to TIFFSetField() function, but actually + * passed as a list of separate values. This behaviour + * must be changed in the future! + */ + int i; + char *val = (char *)tv->value; + + for (i = 0; i < tv->count; i++, val += tv_size) { + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + { + uint8 v = (uint8)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SBYTE: + { + int8 v = (int8)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SHORT: + { + uint16 v = (uint16)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SSHORT: + { + int16 v = (int16)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_LONG: + case TIFF_IFD: + { + uint32 v = va_arg(ap, uint32); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SLONG: + { + int32 v = va_arg(ap, int32); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + { + float v = (float)va_arg(ap, double); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_DOUBLE: + { + double v = va_arg(ap, double); + _TIFFmemcpy(val, &v, tv_size); + } + break; + default: + _TIFFmemset(val, 0, tv_size); + status = 0; + break; + } + } + } + } + } + } + if (status) { + TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + } + +end: + va_end(ap); + return (status); +badvalue: + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %d for \"%s\" tag", + tif->tif_name, v, + _TIFFFieldWithTag(tif, tag)->field_name); + va_end(ap); + return (0); +badvalue32: + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %u for \"%s\" tag", + tif->tif_name, v32, + _TIFFFieldWithTag(tif, tag)->field_name); + va_end(ap); + return (0); +} + +/* + * Return 1/0 according to whether or not + * it is permissible to set the tag's value. + * Note that we allow ImageLength to be changed + * so that we can append and extend to images. + * Any other tag may not be altered once writing + * has commenced, unless its value has no effect + * on the format of the data that is written. + */ +static int +OkToChangeTag(TIFF* tif, ttag_t tag) +{ + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + if (!fip) { /* unknown tag */ + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", "%s: Unknown %stag %u", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag); + return (0); + } + if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) && + !fip->field_oktochange) { + /* + * Consult info table to see if tag can be changed + * after we've started writing. We only allow changes + * to those tags that don't/shouldn't affect the + * compression and/or format of the data. + */ + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", + "%s: Cannot modify tag \"%s\" while writing", + tif->tif_name, fip->field_name); + return (0); + } + return (1); +} + +/* + * Record the value of a field in the + * internal directory structure. The + * field will be written to the file + * when/if the directory structure is + * updated. + */ +int +TIFFSetField(TIFF* tif, ttag_t tag, ...) +{ + va_list ap; + int status; + + va_start(ap, tag); + status = TIFFVSetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Like TIFFSetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + return OkToChangeTag(tif, tag) ? + (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0; +} + +static int +_TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFDirectory* td = &tif->tif_dir; + int ret_val = 1; + + switch (tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32*) = td->td_subfiletype; + break; + case TIFFTAG_IMAGEWIDTH: + *va_arg(ap, uint32*) = td->td_imagewidth; + break; + case TIFFTAG_IMAGELENGTH: + *va_arg(ap, uint32*) = td->td_imagelength; + break; + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16*) = td->td_bitspersample; + break; + case TIFFTAG_COMPRESSION: + *va_arg(ap, uint16*) = td->td_compression; + break; + case TIFFTAG_PHOTOMETRIC: + *va_arg(ap, uint16*) = td->td_photometric; + break; + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16*) = td->td_threshholding; + break; + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16*) = td->td_fillorder; + break; + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16*) = td->td_orientation; + break; + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16*) = td->td_samplesperpixel; + break; + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32*) = td->td_rowsperstrip; + break; + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16*) = td->td_minsamplevalue; + break; + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16*) = td->td_maxsamplevalue; + break; + case TIFFTAG_SMINSAMPLEVALUE: + *va_arg(ap, double*) = td->td_sminsamplevalue; + break; + case TIFFTAG_SMAXSAMPLEVALUE: + *va_arg(ap, double*) = td->td_smaxsamplevalue; + break; + case TIFFTAG_XRESOLUTION: + *va_arg(ap, float*) = td->td_xresolution; + break; + case TIFFTAG_YRESOLUTION: + *va_arg(ap, float*) = td->td_yresolution; + break; + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16*) = td->td_planarconfig; + break; + case TIFFTAG_XPOSITION: + *va_arg(ap, float*) = td->td_xposition; + break; + case TIFFTAG_YPOSITION: + *va_arg(ap, float*) = td->td_yposition; + break; + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16*) = td->td_resolutionunit; + break; + case TIFFTAG_PAGENUMBER: + *va_arg(ap, uint16*) = td->td_pagenumber[0]; + *va_arg(ap, uint16*) = td->td_pagenumber[1]; + break; + case TIFFTAG_HALFTONEHINTS: + *va_arg(ap, uint16*) = td->td_halftonehints[0]; + *va_arg(ap, uint16*) = td->td_halftonehints[1]; + break; + case TIFFTAG_COLORMAP: + *va_arg(ap, uint16**) = td->td_colormap[0]; + *va_arg(ap, uint16**) = td->td_colormap[1]; + *va_arg(ap, uint16**) = td->td_colormap[2]; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + *va_arg(ap, uint32**) = td->td_stripoffset; + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + *va_arg(ap, uint32**) = td->td_stripbytecount; + break; + case TIFFTAG_MATTEING: + *va_arg(ap, uint16*) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + break; + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16*) = td->td_extrasamples; + *va_arg(ap, uint16**) = td->td_sampleinfo; + break; + case TIFFTAG_TILEWIDTH: + *va_arg(ap, uint32*) = td->td_tilewidth; + break; + case TIFFTAG_TILELENGTH: + *va_arg(ap, uint32*) = td->td_tilelength; + break; + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32*) = td->td_tiledepth; + break; + case TIFFTAG_DATATYPE: + switch (td->td_sampleformat) { + case SAMPLEFORMAT_UINT: + *va_arg(ap, uint16*) = DATATYPE_UINT; + break; + case SAMPLEFORMAT_INT: + *va_arg(ap, uint16*) = DATATYPE_INT; + break; + case SAMPLEFORMAT_IEEEFP: + *va_arg(ap, uint16*) = DATATYPE_IEEEFP; + break; + case SAMPLEFORMAT_VOID: + *va_arg(ap, uint16*) = DATATYPE_VOID; + break; + } + break; + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16*) = td->td_sampleformat; + break; + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32*) = td->td_imagedepth; + break; + case TIFFTAG_SUBIFD: + *va_arg(ap, uint16*) = td->td_nsubifd; + *va_arg(ap, uint32**) = td->td_subifd; + break; + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16*) = td->td_ycbcrpositioning; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1]; + break; + case TIFFTAG_TRANSFERFUNCTION: + *va_arg(ap, uint16**) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, uint16**) = td->td_transferfunction[1]; + *va_arg(ap, uint16**) = td->td_transferfunction[2]; + } + break; + case TIFFTAG_REFERENCEBLACKWHITE: + *va_arg(ap, float**) = td->td_refblackwhite; + break; + case TIFFTAG_INKNAMES: + *va_arg(ap, char**) = td->td_inknames; + break; + default: + { + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + int i; + + /* + * This can happen if multiple images are open with different + * codecs which have private tags. The global tag information + * table may then have tags that are valid for one file but not + * the other. If the client tries to get a tag that is not valid + * for the image's codec then we'll arrive here. + */ + if( fip == NULL || fip->field_bit != FIELD_CUSTOM ) + { + TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField", + "%s: Invalid %stag \"%s\" " + "(not supported by codec)", + tif->tif_name, + isPseudoTag(tag) ? "pseudo-" : "", + fip ? fip->field_name : "Unknown"); + ret_val = 0; + break; + } + + /* + * Do we have a custom value? + */ + ret_val = 0; + for (i = 0; i < td->td_customValueCount; i++) { + TIFFTagValue *tv = td->td_customValues + i; + + if (tv->info->field_tag != tag) + continue; + + if (fip->field_passcount) { + if (fip->field_readcount == TIFF_VARIABLE2) + *va_arg(ap, uint32*) = (uint32)tv->count; + else /* Assume TIFF_VARIABLE */ + *va_arg(ap, uint16*) = (uint16)tv->count; + *va_arg(ap, void **) = tv->value; + ret_val = 1; + } else { + if ((fip->field_type == TIFF_ASCII + || fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2 + || fip->field_readcount == TIFF_SPP + || tv->count > 1) + && fip->field_tag != TIFFTAG_PAGENUMBER + && fip->field_tag != TIFFTAG_HALFTONEHINTS + && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING + && fip->field_tag != TIFFTAG_DOTRANGE) { + *va_arg(ap, void **) = tv->value; + ret_val = 1; + } else { + int j; + char *val = (char *)tv->value; + + for (j = 0; j < tv->count; + j++, val += _TIFFDataSize(tv->info->field_type)) { + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + *va_arg(ap, uint8*) = + *(uint8 *)val; + ret_val = 1; + break; + case TIFF_SBYTE: + *va_arg(ap, int8*) = + *(int8 *)val; + ret_val = 1; + break; + case TIFF_SHORT: + *va_arg(ap, uint16*) = + *(uint16 *)val; + ret_val = 1; + break; + case TIFF_SSHORT: + *va_arg(ap, int16*) = + *(int16 *)val; + ret_val = 1; + break; + case TIFF_LONG: + case TIFF_IFD: + *va_arg(ap, uint32*) = + *(uint32 *)val; + ret_val = 1; + break; + case TIFF_SLONG: + *va_arg(ap, int32*) = + *(int32 *)val; + ret_val = 1; + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + *va_arg(ap, float*) = + *(float *)val; + ret_val = 1; + break; + case TIFF_DOUBLE: + *va_arg(ap, double*) = + *(double *)val; + ret_val = 1; + break; + default: + ret_val = 0; + break; + } + } + } + } + break; + } + } + } + return(ret_val); +} + +/* + * Return the value of a field in the + * internal directory structure. + */ +int +TIFFGetField(TIFF* tif, ttag_t tag, ...) +{ + int status; + va_list ap; + + va_start(ap, tag); + status = TIFFVGetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Like TIFFGetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ? + (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0); +} + +#define CleanupField(member) { \ + if (td->member) { \ + _TIFFfree(td->member); \ + td->member = 0; \ + } \ +} + +/* + * Release storage associated with a directory. + */ +void +TIFFFreeDirectory(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + int i; + + _TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS); + CleanupField(td_colormap[0]); + CleanupField(td_colormap[1]); + CleanupField(td_colormap[2]); + CleanupField(td_sampleinfo); + CleanupField(td_subifd); + CleanupField(td_inknames); + CleanupField(td_refblackwhite); + CleanupField(td_transferfunction[0]); + CleanupField(td_transferfunction[1]); + CleanupField(td_transferfunction[2]); + CleanupField(td_stripoffset); + CleanupField(td_stripbytecount); + TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING); + TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING); + + /* Cleanup custom tag values */ + for( i = 0; i < td->td_customValueCount; i++ ) { + if (td->td_customValues[i].value) + _TIFFfree(td->td_customValues[i].value); + } + + td->td_customValueCount = 0; + CleanupField(td_customValues); +} +#undef CleanupField + +/* + * Client Tag extension support (from Niles Ritter). + */ +static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL; + +TIFFExtendProc +TIFFSetTagExtender(TIFFExtendProc extender) +{ + TIFFExtendProc prev = _TIFFextender; + _TIFFextender = extender; + return (prev); +} + +/* + * Setup for a new directory. Should we automatically call + * TIFFWriteDirectory() if the current one is dirty? + * + * The newly created directory will not exist on the file till + * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called. + */ +int +TIFFCreateDirectory(TIFF* tif) +{ + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (tstrip_t) -1; + + return 0; +} + +/* + * Setup a default directory structure. + */ +int +TIFFDefaultDirectory(TIFF* tif) +{ + register TIFFDirectory* td = &tif->tif_dir; + + size_t tiffFieldInfoCount; + const TIFFFieldInfo *tiffFieldInfo = + _TIFFGetFieldInfo(&tiffFieldInfoCount); + _TIFFSetupFieldInfo(tif, tiffFieldInfo, tiffFieldInfoCount); + + _TIFFmemset(td, 0, sizeof (*td)); + td->td_fillorder = FILLORDER_MSB2LSB; + td->td_bitspersample = 1; + td->td_threshholding = THRESHHOLD_BILEVEL; + td->td_orientation = ORIENTATION_TOPLEFT; + td->td_samplesperpixel = 1; + td->td_rowsperstrip = (uint32) -1; + td->td_tilewidth = 0; + td->td_tilelength = 0; + td->td_tiledepth = 1; + td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */ + td->td_resolutionunit = RESUNIT_INCH; + td->td_sampleformat = SAMPLEFORMAT_UINT; + td->td_imagedepth = 1; + td->td_ycbcrsubsampling[0] = 2; + td->td_ycbcrsubsampling[1] = 2; + td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED; + tif->tif_postdecode = _TIFFNoPostDecode; + tif->tif_foundfield = NULL; + tif->tif_tagmethods.vsetfield = _TIFFVSetField; + tif->tif_tagmethods.vgetfield = _TIFFVGetField; + tif->tif_tagmethods.printdir = NULL; + /* + * Give client code a chance to install their own + * tag extensions & methods, prior to compression overloads. + */ + if (_TIFFextender) + (*_TIFFextender)(tif); + (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* + * NB: The directory is marked dirty as a result of setting + * up the default compression scheme. However, this really + * isn't correct -- we want TIFF_DIRTYDIRECT to be set only + * if the user does something. We could just do the setup + * by hand, but it seems better to use the normal mechanism + * (i.e. TIFFSetField). + */ + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + + /* + * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19 + * we clear the ISTILED flag when setting up a new directory. + * Should we also be clearing stuff like INSUBIFD? + */ + tif->tif_flags &= ~TIFF_ISTILED; + /* + * Clear other directory-specific fields. + */ + tif->tif_tilesize = -1; + tif->tif_scanlinesize = -1; + + return (1); +} + +static int +TIFFAdvanceDirectory(TIFF* tif, uint32* nextdir, toff_t* off) +{ + static const char module[] = "TIFFAdvanceDirectory"; + uint16 dircount; + if (isMapped(tif)) + { + toff_t poff=*nextdir; + if (poff+sizeof(uint16) > tif->tif_size) + { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + _TIFFmemcpy(&dircount, tif->tif_base+poff, sizeof (uint16)); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + poff+=sizeof (uint16)+dircount*sizeof (TIFFDirEntry); + if (off != NULL) + *off = poff; + if (((toff_t) (poff+sizeof (uint32))) > tif->tif_size) + { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + _TIFFmemcpy(nextdir, tif->tif_base+poff, sizeof (uint32)); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(nextdir); + return (1); + } + else + { + if (!SeekOK(tif, *nextdir) || + !ReadOK(tif, &dircount, sizeof (uint16))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + if (off != NULL) + *off = TIFFSeekFile(tif, + dircount*sizeof (TIFFDirEntry), SEEK_CUR); + else + (void) TIFFSeekFile(tif, + dircount*sizeof (TIFFDirEntry), SEEK_CUR); + if (!ReadOK(tif, nextdir, sizeof (uint32))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(nextdir); + return (1); + } +} + +/* + * Count the number of directories in a file. + */ +tdir_t +TIFFNumberOfDirectories(TIFF* tif) +{ + toff_t nextdir = tif->tif_header.tiff_diroff; + tdir_t n = 0; + + while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) + n++; + return (n); +} + +/* + * Set the n-th directory as the current directory. + * NB: Directories are numbered starting at 0. + */ +int +TIFFSetDirectory(TIFF* tif, tdir_t dirn) +{ + toff_t nextdir; + tdir_t n; + + nextdir = tif->tif_header.tiff_diroff; + for (n = dirn; n > 0 && nextdir != 0; n--) + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + tif->tif_nextdiroff = nextdir; + /* + * Set curdir to the actual directory index. The + * -1 is because TIFFReadDirectory will increment + * tif_curdir after successfully reading the directory. + */ + tif->tif_curdir = (dirn - n) - 1; + /* + * Reset tif_dirnumber counter and start new list of seen directories. + * We need this to prevent IFD loops. + */ + tif->tif_dirnumber = 0; + return (TIFFReadDirectory(tif)); +} + +/* + * Set the current directory to be the directory + * located at the specified file offset. This interface + * is used mainly to access directories linked with + * the SubIFD tag (e.g. thumbnail images). + */ +int +TIFFSetSubDirectory(TIFF* tif, uint32 diroff) +{ + tif->tif_nextdiroff = diroff; + /* + * Reset tif_dirnumber counter and start new list of seen directories. + * We need this to prevent IFD loops. + */ + tif->tif_dirnumber = 0; + return (TIFFReadDirectory(tif)); +} + +/* + * Return file offset of the current directory. + */ +uint32 +TIFFCurrentDirOffset(TIFF* tif) +{ + return (tif->tif_diroff); +} + +/* + * Return an indication of whether or not we are + * at the last directory in the file. + */ +int +TIFFLastDirectory(TIFF* tif) +{ + return (tif->tif_nextdiroff == 0); +} + +/* + * Unlink the specified directory from the directory chain. + */ +int +TIFFUnlinkDirectory(TIFF* tif, tdir_t dirn) +{ + static const char module[] = "TIFFUnlinkDirectory"; + toff_t nextdir; + toff_t off; + tdir_t n; + + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not unlink directory in read-only file"); + return (0); + } + /* + * Go to the directory before the one we want + * to unlink and nab the offset of the link + * field we'll need to patch. + */ + nextdir = tif->tif_header.tiff_diroff; + off = sizeof (uint16) + sizeof (uint16); + for (n = dirn-1; n > 0; n--) { + if (nextdir == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Directory %d does not exist", dirn); + return (0); + } + if (!TIFFAdvanceDirectory(tif, &nextdir, &off)) + return (0); + } + /* + * Advance to the directory to be unlinked and fetch + * the offset of the directory that follows. + */ + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + /* + * Go back and patch the link field of the preceding + * directory to point to the offset of the directory + * that follows. + */ + (void) TIFFSeekFile(tif, off, SEEK_SET); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir); + if (!WriteOK(tif, &nextdir, sizeof (uint32))) { + TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link"); + return (0); + } + /* + * Leave directory state setup safely. We don't have + * facilities for doing inserting and removing directories, + * so it's safest to just invalidate everything. This + * means that the caller can only append to the directory + * chain. + */ + (*tif->tif_cleanup)(tif); + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE); + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; /* force link on next write */ + tif->tif_nextdiroff = 0; /* next write must be at end */ + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (tstrip_t) -1; + return (1); +} + +/* [BFC] + * + * Author: Bruce Cameron + * + * Set a table of tags that are to be replaced during directory process by the + * 'IGNORE' state - or return TRUE/FALSE for the requested tag such that + * 'ReadDirectory' can use the stored information. + * + * FIXME: this is never used properly. Should be removed in the future. + */ +int +TIFFReassignTagToIgnore (enum TIFFIgnoreSense task, int TIFFtagID) +{ + static int TIFFignoretags [FIELD_LAST]; + static int tagcount = 0 ; + int i; /* Loop index */ + int j; /* Loop index */ + + switch (task) + { + case TIS_STORE: + if ( tagcount < (FIELD_LAST - 1) ) + { + for ( j = 0 ; j < tagcount ; ++j ) + { /* Do not add duplicate tag */ + if ( TIFFignoretags [j] == TIFFtagID ) + return (TRUE) ; + } + TIFFignoretags [tagcount++] = TIFFtagID ; + return (TRUE) ; + } + break ; + + case TIS_EXTRACT: + for ( i = 0 ; i < tagcount ; ++i ) + { + if ( TIFFignoretags [i] == TIFFtagID ) + return (TRUE) ; + } + break; + + case TIS_EMPTY: + tagcount = 0 ; /* Clear the list */ + return (TRUE) ; + + default: + break; + } + + return (FALSE); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_dir.h b/thirdparty/libtiff/tif_dir.h new file mode 100644 index 00000000..515af199 --- /dev/null +++ b/thirdparty/libtiff/tif_dir.h @@ -0,0 +1,211 @@ +/* $Id: tif_dir.h,v 1.30.2.3 2010-06-09 21:15:27 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFDIR_ +#define _TIFFDIR_ +/* + * ``Library-private'' Directory-related Definitions. + */ + +/* + * Internal format of a TIFF directory entry. + */ +typedef struct { +#define FIELD_SETLONGS 4 + /* bit vector of fields that are set */ + unsigned long td_fieldsset[FIELD_SETLONGS]; + + uint32 td_imagewidth, td_imagelength, td_imagedepth; + uint32 td_tilewidth, td_tilelength, td_tiledepth; + uint32 td_subfiletype; + uint16 td_bitspersample; + uint16 td_sampleformat; + uint16 td_compression; + uint16 td_photometric; + uint16 td_threshholding; + uint16 td_fillorder; + uint16 td_orientation; + uint16 td_samplesperpixel; + uint32 td_rowsperstrip; + uint16 td_minsamplevalue, td_maxsamplevalue; + double td_sminsamplevalue, td_smaxsamplevalue; + float td_xresolution, td_yresolution; + uint16 td_resolutionunit; + uint16 td_planarconfig; + float td_xposition, td_yposition; + uint16 td_pagenumber[2]; + uint16* td_colormap[3]; + uint16 td_halftonehints[2]; + uint16 td_extrasamples; + uint16* td_sampleinfo; + /* even though the name is misleading, td_stripsperimage is the number + * of striles (=strips or tiles) per plane, and td_nstrips the total + * number of striles */ + tstrile_t td_stripsperimage; + tstrile_t td_nstrips; /* size of offset & bytecount arrays */ + toff_t* td_stripoffset; + toff_t* td_stripbytecount; /* FIXME: it should be tsize_t array */ + int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ + uint16 td_nsubifd; + uint32* td_subifd; + /* YCbCr parameters */ + uint16 td_ycbcrsubsampling[2]; + uint16 td_ycbcrpositioning; + /* Colorimetry parameters */ + float* td_refblackwhite; + uint16* td_transferfunction[3]; + /* CMYK parameters */ + int td_inknameslen; + char* td_inknames; + + int td_customValueCount; + TIFFTagValue *td_customValues; +} TIFFDirectory; + +/* + * Field flags used to indicate fields that have + * been set in a directory, and to reference fields + * when manipulating a directory. + */ + +/* + * FIELD_IGNORE is used to signify tags that are to + * be processed but otherwise ignored. This permits + * antiquated tags to be quietly read and discarded. + * Note that a bit *is* allocated for ignored tags; + * this is understood by the directory reading logic + * which uses this fact to avoid special-case handling + */ +#define FIELD_IGNORE 0 + +/* multi-item fields */ +#define FIELD_IMAGEDIMENSIONS 1 +#define FIELD_TILEDIMENSIONS 2 +#define FIELD_RESOLUTION 3 +#define FIELD_POSITION 4 + +/* single-item fields */ +#define FIELD_SUBFILETYPE 5 +#define FIELD_BITSPERSAMPLE 6 +#define FIELD_COMPRESSION 7 +#define FIELD_PHOTOMETRIC 8 +#define FIELD_THRESHHOLDING 9 +#define FIELD_FILLORDER 10 +#define FIELD_ORIENTATION 15 +#define FIELD_SAMPLESPERPIXEL 16 +#define FIELD_ROWSPERSTRIP 17 +#define FIELD_MINSAMPLEVALUE 18 +#define FIELD_MAXSAMPLEVALUE 19 +#define FIELD_PLANARCONFIG 20 +#define FIELD_RESOLUTIONUNIT 22 +#define FIELD_PAGENUMBER 23 +#define FIELD_STRIPBYTECOUNTS 24 +#define FIELD_STRIPOFFSETS 25 +#define FIELD_COLORMAP 26 +#define FIELD_EXTRASAMPLES 31 +#define FIELD_SAMPLEFORMAT 32 +#define FIELD_SMINSAMPLEVALUE 33 +#define FIELD_SMAXSAMPLEVALUE 34 +#define FIELD_IMAGEDEPTH 35 +#define FIELD_TILEDEPTH 36 +#define FIELD_HALFTONEHINTS 37 +#define FIELD_YCBCRSUBSAMPLING 39 +#define FIELD_YCBCRPOSITIONING 40 +#define FIELD_REFBLACKWHITE 41 +#define FIELD_TRANSFERFUNCTION 44 +#define FIELD_INKNAMES 46 +#define FIELD_SUBIFD 49 +/* FIELD_CUSTOM (see tiffio.h) 65 */ +/* end of support for well-known tags; codec-private tags follow */ +#define FIELD_CODEC 66 /* base of codec-private tags */ + + +/* + * Pseudo-tags don't normally need field bits since they + * are not written to an output file (by definition). + * The library also has express logic to always query a + * codec for a pseudo-tag so allocating a field bit for + * one is a waste. If codec wants to promote the notion + * of a pseudo-tag being ``set'' or ``unset'' then it can + * do using internal state flags without polluting the + * field bit space defined for real tags. + */ +#define FIELD_PSEUDO 0 + +#define FIELD_LAST (32*FIELD_SETLONGS-1) + +#define TIFFExtractData(tif, type, v) \ + ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \ + ((v) >> (tif)->tif_typeshift[type]) & (tif)->tif_typemask[type] : \ + (v) & (tif)->tif_typemask[type])) +#define TIFFInsertData(tif, type, v) \ + ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \ + ((v) & (tif)->tif_typemask[type]) << (tif)->tif_typeshift[type] : \ + (v) & (tif)->tif_typemask[type])) + + +#define BITn(n) (((unsigned long)1L)<<((n)&0x1f)) +#define BITFIELDn(tif, n) ((tif)->tif_dir.td_fieldsset[(n)/32]) +#define TIFFFieldSet(tif, field) (BITFIELDn(tif, field) & BITn(field)) +#define TIFFSetFieldBit(tif, field) (BITFIELDn(tif, field) |= BITn(field)) +#define TIFFClrFieldBit(tif, field) (BITFIELDn(tif, field) &= ~BITn(field)) + +#define FieldSet(fields, f) (fields[(f)/32] & BITn(f)) +#define ResetFieldBit(fields, f) (fields[(f)/32] &= ~BITn(f)) + +#if defined(__cplusplus) +extern "C" { +#endif +extern const TIFFFieldInfo *_TIFFGetFieldInfo(size_t *); +extern const TIFFFieldInfo *_TIFFGetExifFieldInfo(size_t *); +extern void _TIFFSetupFieldInfo(TIFF*, const TIFFFieldInfo[], size_t); +extern int _TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int); +extern void _TIFFPrintFieldInfo(TIFF*, FILE*); +extern TIFFDataType _TIFFSampleToTagType(TIFF*); +extern const TIFFFieldInfo* _TIFFFindOrRegisterFieldInfo( TIFF *tif, + ttag_t tag, + TIFFDataType dt ); +extern TIFFFieldInfo* _TIFFCreateAnonFieldInfo( TIFF *tif, ttag_t tag, + TIFFDataType dt ); + +#define _TIFFFindFieldInfo TIFFFindFieldInfo +#define _TIFFFindFieldInfoByName TIFFFindFieldInfoByName +#define _TIFFFieldWithTag TIFFFieldWithTag +#define _TIFFFieldWithName TIFFFieldWithName + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFDIR_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_dirinfo.c b/thirdparty/libtiff/tif_dirinfo.c new file mode 100644 index 00000000..57c29d55 --- /dev/null +++ b/thirdparty/libtiff/tif_dirinfo.c @@ -0,0 +1,904 @@ +/* $Id: tif_dirinfo.c,v 1.65.2.9 2010-06-09 21:15:27 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Core Directory Tag Support. + */ +#include "tiffiop.h" +#include +#include + +/* + * NB: NB: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG. + * If a tag can have both LONG and SHORT types then the LONG must be + * placed before the SHORT for writing to work properly. + * + * NOTE: The second field (field_readcount) and third field (field_writecount) + * sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3) + * and TIFFTAG_SPP (-2). The macros should be used but would throw off + * the formatting of the code, so please interprete the -1, -2 and -3 + * values accordingly. + */ +static const TIFFFieldInfo +tiffFieldInfo[] = { + { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, FIELD_SUBFILETYPE, + 1, 0, "SubfileType" }, +/* XXX SHORT for compatibility w/ old versions of the library */ + { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE, + 1, 0, "SubfileType" }, + { TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE, + 1, 0, "OldSubfileType" }, + { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS, + 0, 0, "ImageWidth" }, + { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS, + 0, 0, "ImageWidth" }, + { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS, + 1, 0, "ImageLength" }, + { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS, + 1, 0, "ImageLength" }, + { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_SHORT, FIELD_BITSPERSAMPLE, + 0, 0, "BitsPerSample" }, +/* XXX LONG for compatibility with some broken TIFF writers */ + { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_LONG, FIELD_BITSPERSAMPLE, + 0, 0, "BitsPerSample" }, + { TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, FIELD_COMPRESSION, + 0, 0, "Compression" }, +/* XXX LONG for compatibility with some broken TIFF writers */ + { TIFFTAG_COMPRESSION, -1, 1, TIFF_LONG, FIELD_COMPRESSION, + 0, 0, "Compression" }, + { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, FIELD_PHOTOMETRIC, + 0, 0, "PhotometricInterpretation" }, +/* XXX LONG for compatibility with some broken TIFF writers */ + { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_LONG, FIELD_PHOTOMETRIC, + 0, 0, "PhotometricInterpretation" }, + { TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, FIELD_THRESHHOLDING, + 1, 0, "Threshholding" }, + { TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, FIELD_IGNORE, + 1, 0, "CellWidth" }, + { TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, FIELD_IGNORE, + 1, 0, "CellLength" }, + { TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, FIELD_FILLORDER, + 0, 0, "FillOrder" }, + { TIFFTAG_DOCUMENTNAME, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "DocumentName" }, + { TIFFTAG_IMAGEDESCRIPTION, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "ImageDescription" }, + { TIFFTAG_MAKE, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "Make" }, + { TIFFTAG_MODEL, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "Model" }, + { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_LONG, FIELD_STRIPOFFSETS, + 0, 0, "StripOffsets" }, + { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_SHORT, FIELD_STRIPOFFSETS, + 0, 0, "StripOffsets" }, + { TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, FIELD_ORIENTATION, + 0, 0, "Orientation" }, + { TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, FIELD_SAMPLESPERPIXEL, + 0, 0, "SamplesPerPixel" }, + { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, FIELD_ROWSPERSTRIP, + 0, 0, "RowsPerStrip" }, + { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_SHORT, FIELD_ROWSPERSTRIP, + 0, 0, "RowsPerStrip" }, + { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_STRIPBYTECOUNTS, + 0, 0, "StripByteCounts" }, + { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS, + 0, 0, "StripByteCounts" }, + { TIFFTAG_MINSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MINSAMPLEVALUE, + 1, 0, "MinSampleValue" }, + { TIFFTAG_MAXSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MAXSAMPLEVALUE, + 1, 0, "MaxSampleValue" }, + { TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION, + 1, 0, "XResolution" }, + { TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION, + 1, 0, "YResolution" }, + { TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, FIELD_PLANARCONFIG, + 0, 0, "PlanarConfiguration" }, + { TIFFTAG_PAGENAME, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "PageName" }, + { TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION, + 1, 0, "XPosition" }, + { TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION, + 1, 0, "YPosition" }, + { TIFFTAG_FREEOFFSETS, -1,-1, TIFF_LONG, FIELD_IGNORE, + 0, 0, "FreeOffsets" }, + { TIFFTAG_FREEBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_IGNORE, + 0, 0, "FreeByteCounts" }, + { TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE, + 1, 0, "GrayResponseUnit" }, + { TIFFTAG_GRAYRESPONSECURVE,-1,-1, TIFF_SHORT, FIELD_IGNORE, + 1, 0, "GrayResponseCurve" }, + { TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_RESOLUTIONUNIT, + 1, 0, "ResolutionUnit" }, + { TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, FIELD_PAGENUMBER, + 1, 0, "PageNumber" }, + { TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE, + 1, 0, "ColorResponseUnit" }, + { TIFFTAG_TRANSFERFUNCTION, -1,-1, TIFF_SHORT, FIELD_TRANSFERFUNCTION, + 1, 0, "TransferFunction" }, + { TIFFTAG_SOFTWARE, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "Software" }, + { TIFFTAG_DATETIME, 20,20, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "DateTime" }, + { TIFFTAG_ARTIST, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "Artist" }, + { TIFFTAG_HOSTCOMPUTER, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "HostComputer" }, + { TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "WhitePoint" }, + { TIFFTAG_PRIMARYCHROMATICITIES,6,6,TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "PrimaryChromaticities" }, + { TIFFTAG_COLORMAP, -1,-1, TIFF_SHORT, FIELD_COLORMAP, + 1, 0, "ColorMap" }, + { TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, FIELD_HALFTONEHINTS, + 1, 0, "HalftoneHints" }, + { TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS, + 0, 0, "TileWidth" }, + { TIFFTAG_TILEWIDTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS, + 0, 0, "TileWidth" }, + { TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS, + 0, 0, "TileLength" }, + { TIFFTAG_TILELENGTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS, + 0, 0, "TileLength" }, + { TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG, FIELD_STRIPOFFSETS, + 0, 0, "TileOffsets" }, + { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG, FIELD_STRIPBYTECOUNTS, + 0, 0, "TileByteCounts" }, + { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS, + 0, 0, "TileByteCounts" }, + { TIFFTAG_SUBIFD, -1,-1, TIFF_IFD, FIELD_SUBIFD, + 1, 1, "SubIFD" }, + { TIFFTAG_SUBIFD, -1,-1, TIFF_LONG, FIELD_SUBIFD, + 1, 1, "SubIFD" }, + { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "InkSet" }, + { TIFFTAG_INKNAMES, -1,-1, TIFF_ASCII, FIELD_INKNAMES, + 1, 1, "InkNames" }, + { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "NumberOfInks" }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "DotRange" }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_BYTE, FIELD_CUSTOM, + 0, 0, "DotRange" }, + { TIFFTAG_TARGETPRINTER, -1,-1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "TargetPrinter" }, + { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_SHORT, FIELD_EXTRASAMPLES, + 0, 1, "ExtraSamples" }, +/* XXX for bogus Adobe Photoshop v2.5 files */ + { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_BYTE, FIELD_EXTRASAMPLES, + 0, 1, "ExtraSamples" }, + { TIFFTAG_SAMPLEFORMAT, -1,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT, + 0, 0, "SampleFormat" }, + { TIFFTAG_SMINSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMINSAMPLEVALUE, + 1, 0, "SMinSampleValue" }, + { TIFFTAG_SMAXSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMAXSAMPLEVALUE, + 1, 0, "SMaxSampleValue" }, + { TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, FIELD_CUSTOM, + 0, 1, "ClipPath" }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, FIELD_CUSTOM, + 0, 0, "XClipPathUnits" }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SSHORT, FIELD_CUSTOM, + 0, 0, "XClipPathUnits" }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, FIELD_CUSTOM, + 0, 0, "XClipPathUnits" }, + { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, FIELD_CUSTOM, + 0, 0, "YClipPathUnits" }, + { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SSHORT, FIELD_CUSTOM, + 0, 0, "YClipPathUnits" }, + { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SBYTE, FIELD_CUSTOM, + 0, 0, "YClipPathUnits" }, + { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "YCbCrCoefficients" }, + { TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, FIELD_YCBCRSUBSAMPLING, + 0, 0, "YCbCrSubsampling" }, + { TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, FIELD_YCBCRPOSITIONING, + 0, 0, "YCbCrPositioning" }, + { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, FIELD_REFBLACKWHITE, + 1, 0, "ReferenceBlackWhite" }, +/* XXX temporarily accept LONG for backwards compatibility */ + { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_LONG, FIELD_REFBLACKWHITE, + 1, 0, "ReferenceBlackWhite" }, + { TIFFTAG_XMLPACKET, -3,-3, TIFF_BYTE, FIELD_CUSTOM, + 0, 1, "XMLPacket" }, +/* begin SGI tags */ + { TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, FIELD_EXTRASAMPLES, + 0, 0, "Matteing" }, + { TIFFTAG_DATATYPE, -2,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT, + 0, 0, "DataType" }, + { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, FIELD_IMAGEDEPTH, + 0, 0, "ImageDepth" }, + { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDEPTH, + 0, 0, "ImageDepth" }, + { TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, FIELD_TILEDEPTH, + 0, 0, "TileDepth" }, + { TIFFTAG_TILEDEPTH, 1, 1, TIFF_SHORT, FIELD_TILEDEPTH, + 0, 0, "TileDepth" }, +/* end SGI tags */ +/* begin Pixar tags */ + { TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 1, 0, "ImageFullWidth" }, + { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 1, 0, "ImageFullLength" }, + { TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "TextureFormat" }, + { TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "TextureWrapModes" }, + { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, FIELD_CUSTOM, + 1, 0, "FieldOfViewCotangent" }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16,16, TIFF_FLOAT, + FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen" }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16,16, TIFF_FLOAT, + FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera" }, + { TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "Copyright" }, +/* end Pixar tags */ + { TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, FIELD_CUSTOM, + 0, 1, "RichTIFFIPTC" }, + { TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, FIELD_CUSTOM, + 0, 1, "Photoshop" }, + { TIFFTAG_EXIFIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "EXIFIFDOffset" }, + { TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, + 0, 1, "ICC Profile" }, + { TIFFTAG_GPSIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "GPSIFDOffset" }, + { TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, FIELD_CUSTOM, + 0, 0, "StoNits" }, + { TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "InteroperabilityIFDOffset" }, +/* begin DNG tags */ + { TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, FIELD_CUSTOM, + 0, 0, "DNGVersion" }, + { TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, FIELD_CUSTOM, + 0, 0, "DNGBackwardVersion" }, + { TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "UniqueCameraModel" }, + { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "LocalizedCameraModel" }, + { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, FIELD_CUSTOM, + 1, 1, "LocalizedCameraModel" }, + { TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, FIELD_CUSTOM, + 0, 1, "CFAPlaneColor" }, + { TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "CFALayout" }, + { TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, FIELD_CUSTOM, + 0, 1, "LinearizationTable" }, + { TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "BlackLevelRepeatDim" }, + { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_LONG, FIELD_CUSTOM, + 0, 1, "BlackLevel" }, + { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_SHORT, FIELD_CUSTOM, + 0, 1, "BlackLevel" }, + { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 1, "BlackLevel" }, + { TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "BlackLevelDeltaH" }, + { TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "BlackLevelDeltaV" }, + { TIFFTAG_WHITELEVEL, -2, -2, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "WhiteLevel" }, + { TIFFTAG_WHITELEVEL, -2, -2, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "WhiteLevel" }, + { TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "DefaultScale" }, + { TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "BestQualityScale" }, + { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "DefaultCropOrigin" }, + { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "DefaultCropOrigin" }, + { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "DefaultCropOrigin" }, + { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "DefaultCropSize" }, + { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "DefaultCropSize" }, + { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "DefaultCropSize" }, + { TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "ColorMatrix1" }, + { TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "ColorMatrix2" }, + { TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "CameraCalibration1" }, + { TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "CameraCalibration2" }, + { TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "ReductionMatrix1" }, + { TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "ReductionMatrix2" }, + { TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 1, "AnalogBalance" }, + { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_SHORT, FIELD_CUSTOM, + 0, 1, "AsShotNeutral" }, + { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 1, "AsShotNeutral" }, + { TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "AsShotWhiteXY" }, + { TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 0, "BaselineExposure" }, + { TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "BaselineNoise" }, + { TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "BaselineSharpness" }, + { TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "BayerGreenSplit" }, + { TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "LinearResponseLimit" }, + { TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "CameraSerialNumber" }, + { TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "LensInfo" }, + { TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "ChromaBlurRadius" }, + { TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "AntiAliasStrength" }, + { TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 0, 0, "ShadowScale" }, + { TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, FIELD_CUSTOM, + 0, 1, "DNGPrivateData" }, + { TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "MakerNoteSafety" }, + { TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "CalibrationIlluminant1" }, + { TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "CalibrationIlluminant2" }, + { TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, FIELD_CUSTOM, + 0, 0, "RawDataUniqueID" }, + { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "OriginalRawFileName" }, + { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, FIELD_CUSTOM, + 1, 1, "OriginalRawFileName" }, + { TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 0, 1, "OriginalRawFileData" }, + { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, FIELD_CUSTOM, + 0, 0, "ActiveArea" }, + { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_SHORT, FIELD_CUSTOM, + 0, 0, "ActiveArea" }, + { TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, FIELD_CUSTOM, + 0, 1, "MaskedAreas" }, + { TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 0, 1, "AsShotICCProfile" }, + { TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "AsShotPreProfileMatrix" }, + { TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 0, 1, "CurrentICCProfile" }, + { TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, + 0, 1, "CurrentPreProfileMatrix" }, +/* end DNG tags */ +}; + +static const TIFFFieldInfo +exifFieldInfo[] = { + { EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "ExposureTime" }, + { EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "FNumber" }, + { EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "ExposureProgram" }, + { EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "SpectralSensitivity" }, + { EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, FIELD_CUSTOM, + 1, 1, "ISOSpeedRatings" }, + { EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 1, "OptoelectricConversionFactor" }, + { EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 0, "ExifVersion" }, + { EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "DateTimeOriginal" }, + { EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "DateTimeDigitized" }, + { EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 0, "ComponentsConfiguration" }, + { EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "CompressedBitsPerPixel" }, + { EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, + 1, 0, "ShutterSpeedValue" }, + { EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "ApertureValue" }, + { EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, + 1, 0, "BrightnessValue" }, + { EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, + 1, 0, "ExposureBiasValue" }, + { EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "MaxApertureValue" }, + { EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "SubjectDistance" }, + { EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "MeteringMode" }, + { EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "LightSource" }, + { EXIFTAG_FLASH, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "Flash" }, + { EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "FocalLength" }, + { EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, FIELD_CUSTOM, + 1, 1, "SubjectArea" }, + { EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 1, "MakerNote" }, + { EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 1, "UserComment" }, + { EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "SubSecTime" }, + { EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "SubSecTimeOriginal" }, + { EXIFTAG_SUBSECTIMEDIGITIZED,-1, -1, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "SubSecTimeDigitized" }, + { EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 0, "FlashpixVersion" }, + { EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "ColorSpace" }, + { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 1, 0, "PixelXDimension" }, + { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "PixelXDimension" }, + { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, FIELD_CUSTOM, + 1, 0, "PixelYDimension" }, + { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "PixelYDimension" }, + { EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "RelatedSoundFile" }, + { EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "FlashEnergy" }, + { EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 1, "SpatialFrequencyResponse" }, + { EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "FocalPlaneXResolution" }, + { EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "FocalPlaneYResolution" }, + { EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "FocalPlaneResolutionUnit" }, + { EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "SubjectLocation" }, + { EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "ExposureIndex" }, + { EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "SensingMethod" }, + { EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 0, "FileSource" }, + { EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 0, "SceneType" }, + { EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 1, "CFAPattern" }, + { EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "CustomRendered" }, + { EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "ExposureMode" }, + { EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "WhiteBalance" }, + { EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "DigitalZoomRatio" }, + { EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "FocalLengthIn35mmFilm" }, + { EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "SceneCaptureType" }, + { EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, + 1, 0, "GainControl" }, + { EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "Contrast" }, + { EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "Saturation" }, + { EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "Sharpness" }, + { EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, + 1, 1, "DeviceSettingDescription" }, + { EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, + 1, 0, "SubjectDistanceRange" }, + { EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, FIELD_CUSTOM, + 1, 0, "ImageUniqueID" } +}; + +const TIFFFieldInfo * +_TIFFGetFieldInfo(size_t *size) +{ + *size = TIFFArrayCount(tiffFieldInfo); + return tiffFieldInfo; +} + +const TIFFFieldInfo * +_TIFFGetExifFieldInfo(size_t *size) +{ + *size = TIFFArrayCount(exifFieldInfo); + return exifFieldInfo; +} + +void +_TIFFSetupFieldInfo(TIFF* tif, const TIFFFieldInfo info[], size_t n) +{ + if (tif->tif_fieldinfo) { + size_t i; + + for (i = 0; i < tif->tif_nfields; i++) + { + TIFFFieldInfo *fld = tif->tif_fieldinfo[i]; + if (fld->field_bit == FIELD_CUSTOM && + strncmp("Tag ", fld->field_name, 4) == 0) { + _TIFFfree(fld->field_name); + _TIFFfree(fld); + } + } + + _TIFFfree(tif->tif_fieldinfo); + tif->tif_nfields = 0; + } + if (!_TIFFMergeFieldInfo(tif, info, n)) + { + TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFieldInfo", + "Setting up field info failed"); + } +} + +static int +tagCompare(const void* a, const void* b) +{ + const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a; + const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b; + /* NB: be careful of return values for 16-bit platforms */ + if (ta->field_tag != tb->field_tag) + return (int)ta->field_tag - (int)tb->field_tag; + else + return (ta->field_type == TIFF_ANY) ? + 0 : ((int)tb->field_type - (int)ta->field_type); +} + +static int +tagNameCompare(const void* a, const void* b) +{ + const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a; + const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b; + int ret = strcmp(ta->field_name, tb->field_name); + + if (ret) + return ret; + else + return (ta->field_type == TIFF_ANY) ? + 0 : ((int)tb->field_type - (int)ta->field_type); +} + +void +TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n) +{ + if (_TIFFMergeFieldInfo(tif, info, n) < 0) + { + TIFFErrorExt(tif->tif_clientdata, "TIFFMergeFieldInfo", + "Merging block of %d fields failed", n); + } +} + +int +_TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n) +{ + static const char module[] = "_TIFFMergeFieldInfo"; + static const char reason[] = "for field info array"; + TIFFFieldInfo** tp; + int i; + + tif->tif_foundfield = NULL; + + if (tif->tif_nfields > 0) { + tif->tif_fieldinfo = (TIFFFieldInfo**) + _TIFFCheckRealloc(tif, tif->tif_fieldinfo, + (tif->tif_nfields + n), + sizeof (TIFFFieldInfo*), reason); + } else { + tif->tif_fieldinfo = (TIFFFieldInfo**) + _TIFFCheckMalloc(tif, n, sizeof (TIFFFieldInfo*), + reason); + } + if (!tif->tif_fieldinfo) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate field info array"); + return 0; + } + tp = tif->tif_fieldinfo + tif->tif_nfields; + for (i = 0; i < n; i++) + { + const TIFFFieldInfo *fip = + _TIFFFindFieldInfo(tif, info[i].field_tag, info[i].field_type); + + /* only add definitions that aren't already present */ + if (!fip) { + *tp++ = (TIFFFieldInfo*) (info + i); + tif->tif_nfields++; + } + } + + /* Sort the field info by tag number */ + qsort(tif->tif_fieldinfo, tif->tif_nfields, + sizeof (TIFFFieldInfo*), tagCompare); + + return n; +} + +void +_TIFFPrintFieldInfo(TIFF* tif, FILE* fd) +{ + size_t i; + + fprintf(fd, "%s: \n", tif->tif_name); + for (i = 0; i < tif->tif_nfields; i++) { + const TIFFFieldInfo* fip = tif->tif_fieldinfo[i]; + fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n" + , (int)i + , (unsigned long) fip->field_tag + , fip->field_readcount, fip->field_writecount + , fip->field_type + , fip->field_bit + , fip->field_oktochange ? "TRUE" : "FALSE" + , fip->field_passcount ? "TRUE" : "FALSE" + , fip->field_name + ); + } +} + +/* + * Return size of TIFFDataType in bytes + */ +int +TIFFDataWidth(TIFFDataType type) +{ + switch(type) + { + case 0: /* nothing */ + case 1: /* TIFF_BYTE */ + case 2: /* TIFF_ASCII */ + case 6: /* TIFF_SBYTE */ + case 7: /* TIFF_UNDEFINED */ + return 1; + case 3: /* TIFF_SHORT */ + case 8: /* TIFF_SSHORT */ + return 2; + case 4: /* TIFF_LONG */ + case 9: /* TIFF_SLONG */ + case 11: /* TIFF_FLOAT */ + case 13: /* TIFF_IFD */ + return 4; + case 5: /* TIFF_RATIONAL */ + case 10: /* TIFF_SRATIONAL */ + case 12: /* TIFF_DOUBLE */ + return 8; + default: + return 0; /* will return 0 for unknown types */ + } +} + +/* + * Return size of TIFFDataType in bytes. + * + * XXX: We need a separate function to determine the space needed + * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8, + * but we use 4-byte float to represent rationals. + */ +int +_TIFFDataSize(TIFFDataType type) +{ + switch (type) { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_ASCII: + case TIFF_UNDEFINED: + return 1; + case TIFF_SHORT: + case TIFF_SSHORT: + return 2; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + case TIFF_IFD: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + return 4; + case TIFF_DOUBLE: + return 8; + default: + return 0; + } +} + +/* + * Return nearest TIFFDataType to the sample type of an image. + */ +TIFFDataType +_TIFFSampleToTagType(TIFF* tif) +{ + uint32 bps = TIFFhowmany8(tif->tif_dir.td_bitspersample); + + switch (tif->tif_dir.td_sampleformat) { + case SAMPLEFORMAT_IEEEFP: + return (bps == 4 ? TIFF_FLOAT : TIFF_DOUBLE); + case SAMPLEFORMAT_INT: + return (bps <= 1 ? TIFF_SBYTE : + bps <= 2 ? TIFF_SSHORT : TIFF_SLONG); + case SAMPLEFORMAT_UINT: + return (bps <= 1 ? TIFF_BYTE : + bps <= 2 ? TIFF_SHORT : TIFF_LONG); + case SAMPLEFORMAT_VOID: + return (TIFF_UNDEFINED); + } + /*NOTREACHED*/ + return (TIFF_UNDEFINED); +} + +const TIFFFieldInfo* +_TIFFFindFieldInfo(TIFF* tif, ttag_t tag, TIFFDataType dt) +{ + TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0}; + TIFFFieldInfo* pkey = &key; + const TIFFFieldInfo **ret; + + if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag && + (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type)) + return tif->tif_foundfield; + + /* If we are invoked with no field information, then just return. */ + if ( !tif->tif_fieldinfo ) { + return NULL; + } + + /* NB: use sorted search (e.g. binary search) */ + key.field_tag = tag; + key.field_type = dt; + + ret = (const TIFFFieldInfo **) bsearch(&pkey, + tif->tif_fieldinfo, + tif->tif_nfields, + sizeof(TIFFFieldInfo *), + tagCompare); + return tif->tif_foundfield = (ret ? *ret : NULL); +} + +#undef lfind +static void * +lfind(const void *key, const void *base, size_t *nmemb, size_t size, + int(*compar)(const void *, const void *)) +{ + char *element, *end; + + end = (char *)base + *nmemb * size; + for (element = (char *)base; element < end; element += size) + if (!compar(element, key)) /* key found */ + return element; + + return NULL; +} + + +const TIFFFieldInfo* +_TIFFFindFieldInfoByName(TIFF* tif, const char *field_name, TIFFDataType dt) +{ + TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0}; + TIFFFieldInfo* pkey = &key; + const TIFFFieldInfo **ret; + + if (tif->tif_foundfield + && streq(tif->tif_foundfield->field_name, field_name) + && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type)) + return (tif->tif_foundfield); + + /* If we are invoked with no field information, then just return. */ + if ( !tif->tif_fieldinfo ) { + return NULL; + } + + /* NB: use sorted search (e.g. binary search) */ + key.field_name = (char *)field_name; + key.field_type = dt; + + ret = (const TIFFFieldInfo **) lfind(&pkey, + tif->tif_fieldinfo, + &tif->tif_nfields, + sizeof(TIFFFieldInfo *), + tagNameCompare); + return tif->tif_foundfield = (ret ? *ret : NULL); +} + +const TIFFFieldInfo* +_TIFFFieldWithTag(TIFF* tif, ttag_t tag) +{ + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + if (!fip) { + TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag", + "Internal error, unknown tag 0x%x", + (unsigned int) tag); + assert(fip != NULL); + /*NOTREACHED*/ + } + return (fip); +} + +const TIFFFieldInfo* +_TIFFFieldWithName(TIFF* tif, const char *field_name) +{ + const TIFFFieldInfo* fip = + _TIFFFindFieldInfoByName(tif, field_name, TIFF_ANY); + if (!fip) { + TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName", + "Internal error, unknown tag %s", field_name); + assert(fip != NULL); + /*NOTREACHED*/ + } + return (fip); +} + +const TIFFFieldInfo* +_TIFFFindOrRegisterFieldInfo( TIFF *tif, ttag_t tag, TIFFDataType dt ) + +{ + const TIFFFieldInfo *fld; + + fld = _TIFFFindFieldInfo( tif, tag, dt ); + if( fld == NULL ) + { + fld = _TIFFCreateAnonFieldInfo( tif, tag, dt ); + if (!_TIFFMergeFieldInfo(tif, fld, 1)) + return NULL; + } + + return fld; +} + +TIFFFieldInfo* +_TIFFCreateAnonFieldInfo(TIFF *tif, ttag_t tag, TIFFDataType field_type) +{ + TIFFFieldInfo *fld; + (void) tif; + + fld = (TIFFFieldInfo *) _TIFFmalloc(sizeof (TIFFFieldInfo)); + if (fld == NULL) + return NULL; + _TIFFmemset( fld, 0, sizeof(TIFFFieldInfo) ); + + fld->field_tag = tag; + fld->field_readcount = TIFF_VARIABLE2; + fld->field_writecount = TIFF_VARIABLE2; + fld->field_type = field_type; + fld->field_bit = FIELD_CUSTOM; + fld->field_oktochange = TRUE; + fld->field_passcount = TRUE; + fld->field_name = (char *) _TIFFmalloc(32); + if (fld->field_name == NULL) { + _TIFFfree(fld); + return NULL; + } + + /* + * note that this name is a special sign to TIFFClose() and + * _TIFFSetupFieldInfo() to free the field + */ + sprintf(fld->field_name, "Tag %d", (int) tag); + + return fld; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_dirread.c b/thirdparty/libtiff/tif_dirread.c new file mode 100644 index 00000000..907b5318 --- /dev/null +++ b/thirdparty/libtiff/tif_dirread.c @@ -0,0 +1,2081 @@ +/* $Id: tif_dirread.c,v 1.92.2.9 2010-06-14 00:21:46 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Read Support Routines. + */ +#include "tiffiop.h" + +#define IGNORE 0 /* tag placeholder used below */ + +#ifdef HAVE_IEEEFP +# define TIFFCvtIEEEFloatToNative(tif, n, fp) +# define TIFFCvtIEEEDoubleToNative(tif, n, dp) +#else +extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*); +extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*); +#endif + +static TIFFDirEntry* TIFFReadDirectoryFind(TIFFDirEntry* dir, + uint16 dircount, uint16 tagid); +static int EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16); +static void MissingRequired(TIFF*, const char*); +static int TIFFCheckDirOffset(TIFF*, toff_t); +static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32); +static uint16 TIFFFetchDirectory(TIFF*, toff_t, TIFFDirEntry**, toff_t *); +static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*); +static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*); +static float TIFFFetchRational(TIFF*, TIFFDirEntry*); +static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*); +static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, uint16*); +static int TIFFFetchPerSampleLongs(TIFF*, TIFFDirEntry*, uint32*); +static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*); +static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**); +static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*); +static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*); +static float TIFFFetchFloat(TIFF*, TIFFDirEntry*); +static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*); +static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*); +static void ChopUpSingleUncompressedStrip(TIFF*); + +/* + * Read the next TIFF directory from a file and convert it to the internal + * format. We read directories sequentially. + */ +int +TIFFReadDirectory(TIFF* tif) +{ + static const char module[] = "TIFFReadDirectory"; + + int n; + TIFFDirectory* td; + TIFFDirEntry *dp, *dir = NULL; + uint16 iv; + uint32 v; + const TIFFFieldInfo* fip; + size_t fix; + uint16 dircount; + int diroutoforderwarning = 0, compressionknown = 0; + int haveunknowntags = 0; + + tif->tif_diroff = tif->tif_nextdiroff; + /* + * Check whether we have the last offset or bad offset (IFD looping). + */ + if (!TIFFCheckDirOffset(tif, tif->tif_nextdiroff)) + return 0; + /* + * Cleanup any previous compression state. + */ + (*tif->tif_cleanup)(tif); + tif->tif_curdir++; + dircount = TIFFFetchDirectory(tif, tif->tif_nextdiroff, + &dir, &tif->tif_nextdiroff); + if (!dircount) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Failed to read directory at offset %u", + tif->tif_name, tif->tif_nextdiroff); + return 0; + } + + tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ + /* + * Setup default value and then make a pass over + * the fields to check type and tag information, + * and to extract info required to size data + * structures. A second pass is made afterwards + * to read in everthing not taken in the first pass. + */ + td = &tif->tif_dir; + /* free any old stuff and reinit */ + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + /* + * Electronic Arts writes gray-scale TIFF files + * without a PlanarConfiguration directory entry. + * Thus we setup a default value here, even though + * the TIFF spec says there is no default value. + */ + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + + /* + * Sigh, we must make a separate pass through the + * directory for the following reason: + * + * We must process the Compression tag in the first pass + * in order to merge in codec-private tag definitions (otherwise + * we may get complaints about unknown tags). However, the + * Compression tag may be dependent on the SamplesPerPixel + * tag value because older TIFF specs permited Compression + * to be written as a SamplesPerPixel-count tag entry. + * Thus if we don't first figure out the correct SamplesPerPixel + * tag value then we may end up ignoring the Compression tag + * value because it has an incorrect count value (if the + * true value of SamplesPerPixel is not 1). + * + * It sure would have been nice if Aldus had really thought + * this stuff through carefully. + */ + for (dp = dir, n = dircount; n > 0; n--, dp++) { + if (tif->tif_flags & TIFF_SWAB) { + TIFFSwabArrayOfShort(&dp->tdir_tag, 2); + TIFFSwabArrayOfLong(&dp->tdir_count, 2); + } + if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) { + if (!TIFFFetchNormalTag(tif, dp)) + goto bad; + dp->tdir_tag = IGNORE; + } + } + /* + * First real pass over the directory. + */ + fix = 0; + for (dp = dir, n = dircount; n > 0; n--, dp++) { + + if (dp->tdir_tag == IGNORE) + continue; + if (fix >= tif->tif_nfields) + fix = 0; + + /* + * Silicon Beach (at least) writes unordered + * directory tags (violating the spec). Handle + * it here, but be obnoxious (maybe they'll fix it?). + */ + if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) { + if (!diroutoforderwarning) { + TIFFWarningExt(tif->tif_clientdata, module, + "%s: invalid TIFF directory; tags are not sorted in ascending order", + tif->tif_name); + diroutoforderwarning = 1; + } + fix = 0; /* O(n^2) */ + } + while (fix < tif->tif_nfields && + tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) + fix++; + if (fix >= tif->tif_nfields || + tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { + /* Unknown tag ... we'll deal with it below */ + haveunknowntags = 1; + continue; + } + /* + * Null out old tags that we ignore. + */ + if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { + ignore: + dp->tdir_tag = IGNORE; + continue; + } + /* + * Check data type. + */ + fip = tif->tif_fieldinfo[fix]; + while (dp->tdir_type != (unsigned short) fip->field_type + && fix < tif->tif_nfields) { + if (fip->field_type == TIFF_ANY) /* wildcard */ + break; + fip = tif->tif_fieldinfo[++fix]; + if (fix >= tif->tif_nfields || + fip->field_tag != dp->tdir_tag) { + TIFFWarningExt(tif->tif_clientdata, module, + "%s: wrong data type %d for \"%s\"; tag ignored", + tif->tif_name, dp->tdir_type, + tif->tif_fieldinfo[fix-1]->field_name); + goto ignore; + } + } + /* + * Check count if known in advance. + */ + if (fip->field_readcount != TIFF_VARIABLE + && fip->field_readcount != TIFF_VARIABLE2) { + uint32 expected = (fip->field_readcount == TIFF_SPP) ? + (uint32) td->td_samplesperpixel : + (uint32) fip->field_readcount; + if (!CheckDirCount(tif, dp, expected)) + goto ignore; + } + + switch (dp->tdir_tag) { + case TIFFTAG_COMPRESSION: + /* + * The 5.0 spec says the Compression tag has + * one value, while earlier specs say it has + * one value per sample. Because of this, we + * accept the tag if one value is supplied. + */ + if (dp->tdir_count == 1) { + v = TIFFExtractData(tif, + dp->tdir_type, dp->tdir_offset); + if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v)) + goto bad; + else + compressionknown = 1; + break; + /* XXX: workaround for broken TIFFs */ + } else if (dp->tdir_type == TIFF_LONG) { + if (!TIFFFetchPerSampleLongs(tif, dp, &v) || + !TIFFSetField(tif, dp->tdir_tag, (uint16)v)) + goto bad; + } else { + if (!TIFFFetchPerSampleShorts(tif, dp, &iv) + || !TIFFSetField(tif, dp->tdir_tag, iv)) + goto bad; + } + dp->tdir_tag = IGNORE; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEOFFSETS: + case TIFFTAG_TILEBYTECOUNTS: + TIFFSetFieldBit(tif, fip->field_bit); + break; + case TIFFTAG_IMAGEWIDTH: + case TIFFTAG_IMAGELENGTH: + case TIFFTAG_IMAGEDEPTH: + case TIFFTAG_TILELENGTH: + case TIFFTAG_TILEWIDTH: + case TIFFTAG_TILEDEPTH: + case TIFFTAG_PLANARCONFIG: + case TIFFTAG_ROWSPERSTRIP: + case TIFFTAG_EXTRASAMPLES: + if (!TIFFFetchNormalTag(tif, dp)) + goto bad; + dp->tdir_tag = IGNORE; + break; + } + } + + /* + * If we saw any unknown tags, make an extra pass over the directory + * to deal with them. This must be done separately because the tags + * could have become known when we registered a codec after finding + * the Compression tag. In a correctly-sorted directory there's + * no problem because Compression will come before any codec-private + * tags, but if the sorting is wrong that might not hold. + */ + if (haveunknowntags) { + fix = 0; + for (dp = dir, n = dircount; n > 0; n--, dp++) { + if (dp->tdir_tag == IGNORE) + continue; + if (fix >= tif->tif_nfields || + dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) + fix = 0; /* O(n^2) */ + while (fix < tif->tif_nfields && + tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) + fix++; + if (fix >= tif->tif_nfields || + tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { + + TIFFWarningExt(tif->tif_clientdata, + module, + "%s: unknown field with tag %d (0x%x) encountered", + tif->tif_name, + dp->tdir_tag, + dp->tdir_tag); + + if (!_TIFFMergeFieldInfo(tif, + _TIFFCreateAnonFieldInfo(tif, + dp->tdir_tag, + (TIFFDataType) dp->tdir_type), + 1)) + { + TIFFWarningExt(tif->tif_clientdata, + module, + "Registering anonymous field with tag %d (0x%x) failed", + dp->tdir_tag, + dp->tdir_tag); + dp->tdir_tag = IGNORE; + continue; + } + fix = 0; + while (fix < tif->tif_nfields && + tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) + fix++; + } + /* + * Check data type. + */ + fip = tif->tif_fieldinfo[fix]; + while (dp->tdir_type != (unsigned short) fip->field_type + && fix < tif->tif_nfields) { + if (fip->field_type == TIFF_ANY) /* wildcard */ + break; + fip = tif->tif_fieldinfo[++fix]; + if (fix >= tif->tif_nfields || + fip->field_tag != dp->tdir_tag) { + TIFFWarningExt(tif->tif_clientdata, module, + "%s: wrong data type %d for \"%s\"; tag ignored", + tif->tif_name, dp->tdir_type, + tif->tif_fieldinfo[fix-1]->field_name); + dp->tdir_tag = IGNORE; + break; + } + } + } + } + + /* + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) planarconfig tag says it's separate, + * c) strip offsets/bytecounts tag are both present and + * d) both contain exactly one value, then we consistently find + * that the buggy implementation of the buggy compression scheme + * matches contig planarconfig best. So we 'fix-up' the tag here + */ + if ((td->td_compression==COMPRESSION_OJPEG) && + (td->td_planarconfig==PLANARCONFIG_SEPARATE)) { + dp = TIFFReadDirectoryFind(dir,dircount,TIFFTAG_STRIPOFFSETS); + if ((dp!=0) && (dp->tdir_count==1)) { + dp = TIFFReadDirectoryFind(dir, dircount, + TIFFTAG_STRIPBYTECOUNTS); + if ((dp!=0) && (dp->tdir_count==1)) { + td->td_planarconfig=PLANARCONFIG_CONTIG; + TIFFWarningExt(tif->tif_clientdata, + "TIFFReadDirectory", + "Planarconfig tag value assumed incorrect, " + "assuming data is contig instead of chunky"); + } + } + } + + /* + * Allocate directory structure and setup defaults. + */ + if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { + MissingRequired(tif, "ImageLength"); + goto bad; + } + /* + * Setup appropriate structures (by strip or by tile) + */ + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + td->td_nstrips = TIFFNumberOfStrips(tif); + td->td_tilewidth = td->td_imagewidth; + td->td_tilelength = td->td_rowsperstrip; + td->td_tiledepth = td->td_imagedepth; + tif->tif_flags &= ~TIFF_ISTILED; + } else { + td->td_nstrips = TIFFNumberOfTiles(tif); + tif->tif_flags |= TIFF_ISTILED; + } + if (!td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: cannot handle zero number of %s", + tif->tif_name, isTiled(tif) ? "tiles" : "strips"); + goto bad; + } + td->td_stripsperimage = td->td_nstrips; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + td->td_stripsperimage /= td->td_samplesperpixel; + if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { + if ((td->td_compression==COMPRESSION_OJPEG) && + (isTiled(tif)==0) && + (td->td_nstrips==1)) { + /* + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) it's not a tiled TIFF, + * and c) the number of strips is 1, + * then we tolerate the absence of stripoffsets tag, + * because, presumably, all required data is in the + * JpegInterchangeFormat stream. + */ + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + } else { + MissingRequired(tif, + isTiled(tif) ? "TileOffsets" : "StripOffsets"); + goto bad; + } + } + + /* + * Second pass: extract other information. + */ + for (dp = dir, n = dircount; n > 0; n--, dp++) { + if (dp->tdir_tag == IGNORE) + continue; + switch (dp->tdir_tag) { + case TIFFTAG_MINSAMPLEVALUE: + case TIFFTAG_MAXSAMPLEVALUE: + case TIFFTAG_BITSPERSAMPLE: + case TIFFTAG_DATATYPE: + case TIFFTAG_SAMPLEFORMAT: + /* + * The 5.0 spec says the Compression tag has + * one value, while earlier specs say it has + * one value per sample. Because of this, we + * accept the tag if one value is supplied. + * + * The MinSampleValue, MaxSampleValue, BitsPerSample + * DataType and SampleFormat tags are supposed to be + * written as one value/sample, but some vendors + * incorrectly write one value only -- so we accept + * that as well (yech). Other vendors write correct + * value for NumberOfSamples, but incorrect one for + * BitsPerSample and friends, and we will read this + * too. + */ + if (dp->tdir_count == 1) { + v = TIFFExtractData(tif, + dp->tdir_type, dp->tdir_offset); + if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v)) + goto bad; + /* XXX: workaround for broken TIFFs */ + } else if (dp->tdir_tag == TIFFTAG_BITSPERSAMPLE + && dp->tdir_type == TIFF_LONG) { + if (!TIFFFetchPerSampleLongs(tif, dp, &v) || + !TIFFSetField(tif, dp->tdir_tag, (uint16)v)) + goto bad; + } else { + if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || + !TIFFSetField(tif, dp->tdir_tag, iv)) + goto bad; + } + break; + case TIFFTAG_SMINSAMPLEVALUE: + case TIFFTAG_SMAXSAMPLEVALUE: + { + double dv = 0.0; + if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || + !TIFFSetField(tif, dp->tdir_tag, dv)) + goto bad; + } + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + if (!TIFFFetchStripThing(tif, dp, + td->td_nstrips, &td->td_stripoffset)) + goto bad; + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + if (!TIFFFetchStripThing(tif, dp, + td->td_nstrips, &td->td_stripbytecount)) + goto bad; + break; + case TIFFTAG_COLORMAP: + case TIFFTAG_TRANSFERFUNCTION: + { + char* cp; + /* + * TransferFunction can have either 1x or 3x + * data values; Colormap can have only 3x + * items. + */ + v = 1L<td_bitspersample; + if (dp->tdir_tag == TIFFTAG_COLORMAP || + dp->tdir_count != v) { + if (!CheckDirCount(tif, dp, 3 * v)) + break; + } + v *= sizeof(uint16); + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, + sizeof (uint16), + "to read \"TransferFunction\" tag"); + if (cp != NULL) { + if (TIFFFetchData(tif, dp, cp)) { + /* + * This deals with there being + * only one array to apply to + * all samples. + */ + uint32 c = 1L << td->td_bitspersample; + if (dp->tdir_count == c) + v = 0L; + TIFFSetField(tif, dp->tdir_tag, + cp, cp+v, cp+2*v); + } + _TIFFfree(cp); + } + break; + } + case TIFFTAG_PAGENUMBER: + case TIFFTAG_HALFTONEHINTS: + case TIFFTAG_YCBCRSUBSAMPLING: + case TIFFTAG_DOTRANGE: + (void) TIFFFetchShortPair(tif, dp); + break; + case TIFFTAG_REFERENCEBLACKWHITE: + (void) TIFFFetchRefBlackWhite(tif, dp); + break; +/* BEGIN REV 4.0 COMPATIBILITY */ + case TIFFTAG_OSUBFILETYPE: + v = 0L; + switch (TIFFExtractData(tif, dp->tdir_type, + dp->tdir_offset)) { + case OFILETYPE_REDUCEDIMAGE: + v = FILETYPE_REDUCEDIMAGE; + break; + case OFILETYPE_PAGE: + v = FILETYPE_PAGE; + break; + } + if (v) + TIFFSetField(tif, TIFFTAG_SUBFILETYPE, v); + break; +/* END REV 4.0 COMPATIBILITY */ + default: + (void) TIFFFetchNormalTag(tif, dp); + break; + } + } + /* + * OJPEG hack: + * - If a) compression is OJPEG, and b) photometric tag is missing, + * then we consistently find that photometric should be YCbCr + * - If a) compression is OJPEG, and b) photometric tag says it's RGB, + * then we consistently find that the buggy implementation of the + * buggy compression scheme matches photometric YCbCr instead. + * - If a) compression is OJPEG, and b) bitspersample tag is missing, + * then we consistently find bitspersample should be 8. + * - If a) compression is OJPEG, b) samplesperpixel tag is missing, + * and c) photometric is RGB or YCbCr, then we consistently find + * samplesperpixel should be 3 + * - If a) compression is OJPEG, b) samplesperpixel tag is missing, + * and c) photometric is MINISWHITE or MINISBLACK, then we consistently + * find samplesperpixel should be 3 + */ + if (td->td_compression==COMPRESSION_OJPEG) + { + if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) + { + TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory", + "Photometric tag is missing, assuming data is YCbCr"); + if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR)) + goto bad; + } + else if (td->td_photometric==PHOTOMETRIC_RGB) + { + td->td_photometric=PHOTOMETRIC_YCBCR; + TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory", + "Photometric tag value assumed incorrect, " + "assuming data is YCbCr instead of RGB"); + } + if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + { + TIFFWarningExt(tif->tif_clientdata,"TIFFReadDirectory", + "BitsPerSample tag is missing, assuming 8 bits per sample"); + if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8)) + goto bad; + } + if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + { + if ((td->td_photometric==PHOTOMETRIC_RGB) + || (td->td_photometric==PHOTOMETRIC_YCBCR)) + { + TIFFWarningExt(tif->tif_clientdata, + "TIFFReadDirectory", + "SamplesPerPixel tag is missing, " + "assuming correct SamplesPerPixel value is 3"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) + goto bad; + } + else if ((td->td_photometric==PHOTOMETRIC_MINISWHITE) + || (td->td_photometric==PHOTOMETRIC_MINISBLACK)) + { + TIFFWarningExt(tif->tif_clientdata, + "TIFFReadDirectory", + "SamplesPerPixel tag is missing, " + "assuming correct SamplesPerPixel value is 1"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1)) + goto bad; + } + } + } + /* + * Verify Palette image has a Colormap. + */ + if (td->td_photometric == PHOTOMETRIC_PALETTE && + !TIFFFieldSet(tif, FIELD_COLORMAP)) { + MissingRequired(tif, "Colormap"); + goto bad; + } + /* + * OJPEG hack: + * We do no further messing with strip/tile offsets/bytecounts in OJPEG + * TIFFs + */ + if (td->td_compression!=COMPRESSION_OJPEG) + { + /* + * Attempt to deal with a missing StripByteCounts tag. + */ + if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { + /* + * Some manufacturers violate the spec by not giving + * the size of the strips. In this case, assume there + * is one uncompressed strip of data. + */ + if ((td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_nstrips > 1) || + (td->td_planarconfig == PLANARCONFIG_SEPARATE && + td->td_nstrips != td->td_samplesperpixel)) { + MissingRequired(tif, "StripByteCounts"); + goto bad; + } + TIFFWarningExt(tif->tif_clientdata, module, + "%s: TIFF directory is missing required " + "\"%s\" field, calculating from imagelength", + tif->tif_name, + _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + /* + * Assume we have wrong StripByteCount value (in case + * of single strip) in following cases: + * - it is equal to zero along with StripOffset; + * - it is larger than file itself (in case of uncompressed + * image); + * - it is smaller than the size of the bytes per row + * multiplied on the number of rows. The last case should + * not be checked in the case of writing new image, + * because we may do not know the exact strip size + * until the whole image will be written and directory + * dumped out. + */ + #define BYTECOUNTLOOKSBAD \ + ( (td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \ + (td->td_compression == COMPRESSION_NONE && \ + td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0]) || \ + (tif->tif_mode == O_RDONLY && \ + td->td_compression == COMPRESSION_NONE && \ + td->td_stripbytecount[0] < TIFFScanlineSize(tif) * td->td_imagelength) ) + + } else if (td->td_nstrips == 1 + && td->td_stripoffset[0] != 0 + && BYTECOUNTLOOKSBAD) { + /* + * XXX: Plexus (and others) sometimes give a value of + * zero for a tag when they don't know what the + * correct value is! Try and handle the simple case + * of estimating the size of a one strip image. + */ + TIFFWarningExt(tif->tif_clientdata, module, + "%s: Bogus \"%s\" field, ignoring and calculating from imagelength", + tif->tif_name, + _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); + if(EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + } else if (td->td_planarconfig == PLANARCONFIG_CONTIG + && td->td_nstrips > 2 + && td->td_compression == COMPRESSION_NONE + && td->td_stripbytecount[0] != td->td_stripbytecount[1] + && td->td_stripbytecount[0] != 0 + && td->td_stripbytecount[1] != 0 ) { + /* + * XXX: Some vendors fill StripByteCount array with + * absolutely wrong values (it can be equal to + * StripOffset array, for example). Catch this case + * here. + */ + TIFFWarningExt(tif->tif_clientdata, module, + "%s: Wrong \"%s\" field, ignoring and calculating from imagelength", + tif->tif_name, + _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + } + } + if (dir) { + _TIFFfree((char *)dir); + dir = NULL; + } + if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) + td->td_maxsamplevalue = (uint16)((1L<td_bitspersample)-1); + /* + * Setup default compression scheme. + */ + + /* + * XXX: We can optimize checking for the strip bounds using the sorted + * bytecounts array. See also comments for TIFFAppendToStrip() + * function in tif_write.c. + */ + if (td->td_nstrips > 1) { + tstrip_t strip; + + td->td_stripbytecountsorted = 1; + for (strip = 1; strip < td->td_nstrips; strip++) { + if (td->td_stripoffset[strip - 1] > + td->td_stripoffset[strip]) { + td->td_stripbytecountsorted = 0; + break; + } + } + } + + if (!TIFFFieldSet(tif, FIELD_COMPRESSION)) + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* + * Some manufacturers make life difficult by writing + * large amounts of uncompressed data as a single strip. + * This is contrary to the recommendations of the spec. + * The following makes an attempt at breaking such images + * into strips closer to the recommended 8k bytes. A + * side effect, however, is that the RowsPerStrip tag + * value may be changed. + */ + if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE && + (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP) + ChopUpSingleUncompressedStrip(tif); + + /* + * Reinitialize i/o since we are starting on a new directory. + */ + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (tstrip_t) -1; + tif->tif_col = (uint32) -1; + tif->tif_curtile = (ttile_t) -1; + tif->tif_tilesize = (tsize_t) -1; + + tif->tif_scanlinesize = TIFFScanlineSize(tif); + if (!tif->tif_scanlinesize) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: cannot handle zero scanline size", + tif->tif_name); + return (0); + } + + if (isTiled(tif)) { + tif->tif_tilesize = TIFFTileSize(tif); + if (!tif->tif_tilesize) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: cannot handle zero tile size", + tif->tif_name); + return (0); + } + } else { + if (!TIFFStripSize(tif)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: cannot handle zero strip size", + tif->tif_name); + return (0); + } + } + return (1); +bad: + if (dir) + _TIFFfree(dir); + return (0); +} + +static TIFFDirEntry* +TIFFReadDirectoryFind(TIFFDirEntry* dir, uint16 dircount, uint16 tagid) +{ + TIFFDirEntry* m; + uint16 n; + for (m=dir, n=0; ntdir_tag==tagid) + return(m); + } + return(0); +} + +/* + * Read custom directory from the arbitarry offset. + * The code is very similar to TIFFReadDirectory(). + */ +int +TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, + const TIFFFieldInfo info[], size_t n) +{ + static const char module[] = "TIFFReadCustomDirectory"; + + TIFFDirectory* td = &tif->tif_dir; + TIFFDirEntry *dp, *dir = NULL; + const TIFFFieldInfo* fip; + size_t fix; + uint16 i, dircount; + + _TIFFSetupFieldInfo(tif, info, n); + + dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL); + if (!dircount) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Failed to read custom directory at offset %u", + tif->tif_name, diroff); + return 0; + } + + TIFFFreeDirectory(tif); + _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory)); + + fix = 0; + for (dp = dir, i = dircount; i > 0; i--, dp++) { + if (tif->tif_flags & TIFF_SWAB) { + TIFFSwabArrayOfShort(&dp->tdir_tag, 2); + TIFFSwabArrayOfLong(&dp->tdir_count, 2); + } + + if (fix >= tif->tif_nfields || dp->tdir_tag == IGNORE) + continue; + + while (fix < tif->tif_nfields && + tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) + fix++; + + if (fix >= tif->tif_nfields || + tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { + + TIFFWarningExt(tif->tif_clientdata, module, + "%s: unknown field with tag %d (0x%x) encountered", + tif->tif_name, dp->tdir_tag, dp->tdir_tag); + if (!_TIFFMergeFieldInfo(tif, + _TIFFCreateAnonFieldInfo(tif, + dp->tdir_tag, + (TIFFDataType) dp->tdir_type), + 1)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Registering anonymous field with tag %d (0x%x) failed", + dp->tdir_tag, dp->tdir_tag); + goto ignore; + } + + fix = 0; + while (fix < tif->tif_nfields && + tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) + fix++; + } + /* + * Null out old tags that we ignore. + */ + if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { + ignore: + dp->tdir_tag = IGNORE; + continue; + } + /* + * Check data type. + */ + fip = tif->tif_fieldinfo[fix]; + while (dp->tdir_type != (unsigned short) fip->field_type + && fix < tif->tif_nfields) { + if (fip->field_type == TIFF_ANY) /* wildcard */ + break; + fip = tif->tif_fieldinfo[++fix]; + if (fix >= tif->tif_nfields || + fip->field_tag != dp->tdir_tag) { + TIFFWarningExt(tif->tif_clientdata, module, + "%s: wrong data type %d for \"%s\"; tag ignored", + tif->tif_name, dp->tdir_type, + tif->tif_fieldinfo[fix-1]->field_name); + goto ignore; + } + } + /* + * Check count if known in advance. + */ + if (fip->field_readcount != TIFF_VARIABLE + && fip->field_readcount != TIFF_VARIABLE2) { + uint32 expected = (fip->field_readcount == TIFF_SPP) ? + (uint32) td->td_samplesperpixel : + (uint32) fip->field_readcount; + if (!CheckDirCount(tif, dp, expected)) + goto ignore; + } + + /* + * EXIF tags which need to be specifically processed. + */ + switch (dp->tdir_tag) { + case EXIFTAG_SUBJECTDISTANCE: + (void) TIFFFetchSubjectDistance(tif, dp); + break; + default: + (void) TIFFFetchNormalTag(tif, dp); + break; + } + } + + if (dir) + _TIFFfree(dir); + return 1; +} + +/* + * EXIF is important special case of custom IFD, so we have a special + * function to read it. + */ +int +TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff) +{ + size_t exifFieldInfoCount; + const TIFFFieldInfo *exifFieldInfo = + _TIFFGetExifFieldInfo(&exifFieldInfoCount); + return TIFFReadCustomDirectory(tif, diroff, exifFieldInfo, + exifFieldInfoCount); +} + +static int +EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) +{ + static const char module[] = "EstimateStripByteCounts"; + + TIFFDirEntry *dp; + TIFFDirectory *td = &tif->tif_dir; + uint32 strip; + + if (td->td_stripbytecount) + _TIFFfree(td->td_stripbytecount); + td->td_stripbytecount = (uint32*) + _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint32), + "for \"StripByteCounts\" array"); + if( td->td_stripbytecount == NULL ) + return -1; + + if (td->td_compression != COMPRESSION_NONE) { + uint32 space = (uint32)(sizeof (TIFFHeader) + + sizeof (uint16) + + (dircount * sizeof (TIFFDirEntry)) + + sizeof (uint32)); + toff_t filesize = TIFFGetFileSize(tif); + uint16 n; + + /* calculate amount of space used by indirect values */ + for (dp = dir, n = dircount; n > 0; n--, dp++) + { + uint32 cc = TIFFDataWidth((TIFFDataType) dp->tdir_type); + if (cc == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Cannot determine size of unknown tag type %d", + tif->tif_name, dp->tdir_type); + return -1; + } + cc = cc * dp->tdir_count; + if (cc > sizeof (uint32)) + space += cc; + } + space = filesize - space; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + space /= td->td_samplesperpixel; + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount[strip] = space; + /* + * This gross hack handles the case were the offset to + * the last strip is past the place where we think the strip + * should begin. Since a strip of data must be contiguous, + * it's safe to assume that we've overestimated the amount + * of data in the strip and trim this number back accordingly. + */ + strip--; + if (((toff_t)(td->td_stripoffset[strip]+ + td->td_stripbytecount[strip])) > filesize) + td->td_stripbytecount[strip] = + filesize - td->td_stripoffset[strip]; + } else if (isTiled(tif)) { + uint32 bytespertile = TIFFTileSize(tif); + + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount[strip] = bytespertile; + } else { + uint32 rowbytes = TIFFScanlineSize(tif); + uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage; + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount[strip] = rowbytes * rowsperstrip; + } + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) + td->td_rowsperstrip = td->td_imagelength; + return 1; +} + +static void +MissingRequired(TIFF* tif, const char* tagname) +{ + static const char module[] = "MissingRequired"; + + TIFFErrorExt(tif->tif_clientdata, module, + "%s: TIFF directory is missing required \"%s\" field", + tif->tif_name, tagname); +} + +/* + * Check the directory offset against the list of already seen directory + * offsets. This is a trick to prevent IFD looping. The one can create TIFF + * file with looped directory pointers. We will maintain a list of already + * seen directories and check every IFD offset against that list. + */ +static int +TIFFCheckDirOffset(TIFF* tif, toff_t diroff) +{ + uint16 n; + + if (diroff == 0) /* no more directories */ + return 0; + + for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) { + if (tif->tif_dirlist[n] == diroff) + return 0; + } + + tif->tif_dirnumber++; + + if (tif->tif_dirnumber > tif->tif_dirlistsize) { + toff_t* new_dirlist; + + /* + * XXX: Reduce memory allocation granularity of the dirlist + * array. + */ + new_dirlist = (toff_t *)_TIFFCheckRealloc(tif, + tif->tif_dirlist, + tif->tif_dirnumber, + 2 * sizeof(toff_t), + "for IFD list"); + if (!new_dirlist) + return 0; + tif->tif_dirlistsize = 2 * tif->tif_dirnumber; + tif->tif_dirlist = new_dirlist; + } + + tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff; + + return 1; +} + +/* + * Check the count field of a directory entry against a known value. The + * caller is expected to skip/ignore the tag if there is a mismatch. + */ +static int +CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count) +{ + if (count > dir->tdir_count) { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count for field \"%s\" (%u, expecting %u); tag ignored", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, + dir->tdir_count, count); + return (0); + } else if (count < dir->tdir_count) { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count for field \"%s\" (%u, expecting %u); tag trimmed", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, + dir->tdir_count, count); + return (1); + } + return (1); +} + +/* + * Read IFD structure from the specified offset. If the pointer to + * nextdiroff variable has been specified, read it too. Function returns a + * number of fields in the directory or 0 if failed. + */ +static uint16 +TIFFFetchDirectory(TIFF* tif, toff_t diroff, TIFFDirEntry **pdir, + toff_t *nextdiroff) +{ + static const char module[] = "TIFFFetchDirectory"; + + TIFFDirEntry *dir; + uint16 dircount; + + assert(pdir); + + tif->tif_diroff = diroff; + if (nextdiroff) + *nextdiroff = 0; + if (!isMapped(tif)) { + if (!SeekOK(tif, tif->tif_diroff)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + if (!ReadOK(tif, &dircount, sizeof (uint16))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount, + sizeof (TIFFDirEntry), + "to read TIFF directory"); + if (dir == NULL) + return 0; + if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%.100s: Can not read TIFF directory", + tif->tif_name); + _TIFFfree(dir); + return 0; + } + /* + * Read offset to next directory for sequential scans if + * needed. + */ + if (nextdiroff) + (void) ReadOK(tif, nextdiroff, sizeof(uint32)); + } else { + toff_t off = tif->tif_diroff; + + /* + * Check for integer overflow when validating the dir_off, + * otherwise a very high offset may cause an OOB read and + * crash the client. Make two comparisons instead of + * + * off + sizeof(uint16) > tif->tif_size + * + * to avoid overflow. + */ + if (tif->tif_size < sizeof (uint16) || + off > tif->tif_size - sizeof(uint16)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } else { + _TIFFmemcpy(&dircount, tif->tif_base + off, + sizeof(uint16)); + } + off += sizeof (uint16); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount, + sizeof(TIFFDirEntry), + "to read TIFF directory"); + if (dir == NULL) + return 0; + if (off + dircount * sizeof (TIFFDirEntry) > tif->tif_size) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory", + tif->tif_name); + _TIFFfree(dir); + return 0; + } else { + _TIFFmemcpy(dir, tif->tif_base + off, + dircount * sizeof(TIFFDirEntry)); + } + if (nextdiroff) { + off += dircount * sizeof (TIFFDirEntry); + if (off + sizeof (uint32) <= tif->tif_size) { + _TIFFmemcpy(nextdiroff, tif->tif_base + off, + sizeof (uint32)); + } + } + } + if (nextdiroff && tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(nextdiroff); + *pdir = dir; + return dircount; +} + +/* + * Fetch a contiguous directory item. + */ +static tsize_t +TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + uint32 w = TIFFDataWidth((TIFFDataType) dir->tdir_type); + /* + * FIXME: butecount should have tsize_t type, but for now libtiff + * defines tsize_t as a signed 32-bit integer and we are losing + * ability to read arrays larger than 2^31 bytes. So we are using + * uint32 instead of tsize_t here. + */ + uint32 cc = dir->tdir_count * w; + + /* Check for overflow. */ + if (!dir->tdir_count || !w || cc / w != dir->tdir_count) + goto bad; + + if (!isMapped(tif)) { + if (!SeekOK(tif, dir->tdir_offset)) + goto bad; + if (!ReadOK(tif, cp, cc)) + goto bad; + } else { + /* Check for overflow. */ + if (dir->tdir_offset + cc < dir->tdir_offset + || dir->tdir_offset + cc < cc + || dir->tdir_offset + cc > tif->tif_size) + goto bad; + _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc); + } + if (tif->tif_flags & TIFF_SWAB) { + switch (dir->tdir_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); + break; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); + break; + case TIFF_DOUBLE: + TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); + break; + } + } + return (cc); +bad: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error fetching data for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + return (tsize_t) 0; +} + +/* + * Fetch an ASCII item from the file. + */ +static tsize_t +TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + if (dir->tdir_count <= 4) { + uint32 l = dir->tdir_offset; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&l); + _TIFFmemcpy(cp, &l, dir->tdir_count); + return (1); + } + return (TIFFFetchData(tif, dir, cp)); +} + +/* + * Convert numerator+denominator to float. + */ +static int +cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv) +{ + if (denom == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s: Rational with zero denominator (num = %u)", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num); + return (0); + } else { + if (dir->tdir_type == TIFF_RATIONAL) + *rv = ((float)num / (float)denom); + else + *rv = ((float)(int32)num / (float)(int32)denom); + return (1); + } +} + +/* + * Fetch a rational item from the file at offset off and return the value as a + * floating point number. + */ +static float +TIFFFetchRational(TIFF* tif, TIFFDirEntry* dir) +{ + uint32 l[2]; + float v; + + return (!TIFFFetchData(tif, dir, (char *)l) || + !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v); +} + +/* + * Fetch a single floating point value from the offset field and return it as + * a native float. + */ +static float +TIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir) +{ + float v; + int32 l = TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset); + _TIFFmemcpy(&v, &l, sizeof(float)); + TIFFCvtIEEEFloatToNative(tif, 1, &v); + return (v); +} + +/* + * Fetch an array of BYTE or SBYTE values. + */ +static int +TIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint8* v) +{ + if (dir->tdir_count <= 4) { + /* + * Extract data from offset field. + */ + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + if (dir->tdir_type == TIFF_SBYTE) + switch (dir->tdir_count) { + case 4: v[3] = dir->tdir_offset & 0xff; + case 3: v[2] = (dir->tdir_offset >> 8) & 0xff; + case 2: v[1] = (dir->tdir_offset >> 16) & 0xff; + case 1: v[0] = dir->tdir_offset >> 24; + } + else + switch (dir->tdir_count) { + case 4: v[3] = dir->tdir_offset & 0xff; + case 3: v[2] = (dir->tdir_offset >> 8) & 0xff; + case 2: v[1] = (dir->tdir_offset >> 16) & 0xff; + case 1: v[0] = dir->tdir_offset >> 24; + } + } else { + if (dir->tdir_type == TIFF_SBYTE) + switch (dir->tdir_count) { + case 4: v[3] = dir->tdir_offset >> 24; + case 3: v[2] = (dir->tdir_offset >> 16) & 0xff; + case 2: v[1] = (dir->tdir_offset >> 8) & 0xff; + case 1: v[0] = dir->tdir_offset & 0xff; + } + else + switch (dir->tdir_count) { + case 4: v[3] = dir->tdir_offset >> 24; + case 3: v[2] = (dir->tdir_offset >> 16) & 0xff; + case 2: v[1] = (dir->tdir_offset >> 8) & 0xff; + case 1: v[0] = dir->tdir_offset & 0xff; + } + } + return (1); + } else + return (TIFFFetchData(tif, dir, (char*) v) != 0); /* XXX */ +} + +/* + * Fetch an array of SHORT or SSHORT values. + */ +static int +TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v) +{ + if (dir->tdir_count <= 2) { + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + switch (dir->tdir_count) { + case 2: v[1] = (uint16) (dir->tdir_offset & 0xffff); + case 1: v[0] = (uint16) (dir->tdir_offset >> 16); + } + } else { + switch (dir->tdir_count) { + case 2: v[1] = (uint16) (dir->tdir_offset >> 16); + case 1: v[0] = (uint16) (dir->tdir_offset & 0xffff); + } + } + return (1); + } else + return (TIFFFetchData(tif, dir, (char *)v) != 0); +} + +/* + * Fetch a pair of SHORT or BYTE values. Some tags may have either BYTE + * or SHORT type and this function works with both ones. + */ +static int +TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir) +{ + /* + * Prevent overflowing the v stack arrays below by performing a sanity + * check on tdir_count, this should never be greater than two. + */ + if (dir->tdir_count > 2) { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "unexpected count for field \"%s\", %u, expected 2; ignored", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, + dir->tdir_count); + return 0; + } + + switch (dir->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + { + uint8 v[4]; + return TIFFFetchByteArray(tif, dir, v) + && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); + } + case TIFF_SHORT: + case TIFF_SSHORT: + { + uint16 v[2]; + return TIFFFetchShortArray(tif, dir, v) + && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); + } + default: + return 0; + } +} + +/* + * Fetch an array of LONG or SLONG values. + */ +static int +TIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v) +{ + if (dir->tdir_count == 1) { + v[0] = dir->tdir_offset; + return (1); + } else + return (TIFFFetchData(tif, dir, (char*) v) != 0); +} + +/* + * Fetch an array of RATIONAL or SRATIONAL values. + */ +static int +TIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v) +{ + int ok = 0; + uint32* l; + + l = (uint32*)_TIFFCheckMalloc(tif, + dir->tdir_count, TIFFDataWidth((TIFFDataType) dir->tdir_type), + "to fetch array of rationals"); + if (l) { + if (TIFFFetchData(tif, dir, (char *)l)) { + uint32 i; + for (i = 0; i < dir->tdir_count; i++) { + ok = cvtRational(tif, dir, + l[2*i+0], l[2*i+1], &v[i]); + if (!ok) + break; + } + } + _TIFFfree((char *)l); + } + return (ok); +} + +/* + * Fetch an array of FLOAT values. + */ +static int +TIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v) +{ + + if (dir->tdir_count == 1) { + union + { + float f; + uint32 i; + } float_union; + + float_union.i=dir->tdir_offset; + v[0]=float_union.f; + TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v); + return (1); + } else if (TIFFFetchData(tif, dir, (char*) v)) { + TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v); + return (1); + } else + return (0); +} + +/* + * Fetch an array of DOUBLE values. + */ +static int +TIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v) +{ + if (TIFFFetchData(tif, dir, (char*) v)) { + TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v); + return (1); + } else + return (0); +} + +/* + * Fetch an array of ANY values. The actual values are returned as doubles + * which should be able hold all the types. Yes, there really should be an + * tany_t to avoid this potential non-portability ... Note in particular that + * we assume that the double return value vector is large enough to read in + * any fundamental type. We use that vector as a buffer to read in the base + * type vector and then convert it in place to double (from end to front of + * course). + */ +static int +TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v) +{ + int i; + + switch (dir->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + if (!TIFFFetchByteArray(tif, dir, (uint8*) v)) + return (0); + if (dir->tdir_type == TIFF_BYTE) { + uint8* vp = (uint8*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } else { + int8* vp = (int8*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_SHORT: + case TIFF_SSHORT: + if (!TIFFFetchShortArray(tif, dir, (uint16*) v)) + return (0); + if (dir->tdir_type == TIFF_SHORT) { + uint16* vp = (uint16*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } else { + int16* vp = (int16*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_LONG: + case TIFF_SLONG: + if (!TIFFFetchLongArray(tif, dir, (uint32*) v)) + return (0); + if (dir->tdir_type == TIFF_LONG) { + uint32* vp = (uint32*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } else { + int32* vp = (int32*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + if (!TIFFFetchRationalArray(tif, dir, (float*) v)) + return (0); + { float* vp = (float*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_FLOAT: + if (!TIFFFetchFloatArray(tif, dir, (float*) v)) + return (0); + { float* vp = (float*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_DOUBLE: + return (TIFFFetchDoubleArray(tif, dir, (double*) v)); + default: + /* TIFF_NOTYPE */ + /* TIFF_ASCII */ + /* TIFF_UNDEFINED */ + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "cannot read TIFF_ANY type %d for field \"%s\"", + dir->tdir_type, + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + return (0); + } + return (1); +} + +/* + * Fetch a tag that is not handled by special case code. + */ +static int +TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp) +{ + static const char mesg[] = "to fetch tag value"; + int ok = 0; + const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dp->tdir_tag); + + if (dp->tdir_count > 1) { /* array of values */ + char* cp = NULL; + + switch (dp->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, sizeof (uint8), mesg); + ok = cp && TIFFFetchByteArray(tif, dp, (uint8*) cp); + break; + case TIFF_SHORT: + case TIFF_SSHORT: + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, sizeof (uint16), mesg); + ok = cp && TIFFFetchShortArray(tif, dp, (uint16*) cp); + break; + case TIFF_LONG: + case TIFF_SLONG: + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, sizeof (uint32), mesg); + ok = cp && TIFFFetchLongArray(tif, dp, (uint32*) cp); + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, sizeof (float), mesg); + ok = cp && TIFFFetchRationalArray(tif, dp, (float*) cp); + break; + case TIFF_FLOAT: + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, sizeof (float), mesg); + ok = cp && TIFFFetchFloatArray(tif, dp, (float*) cp); + break; + case TIFF_DOUBLE: + cp = (char *)_TIFFCheckMalloc(tif, + dp->tdir_count, sizeof (double), mesg); + ok = cp && TIFFFetchDoubleArray(tif, dp, (double*) cp); + break; + case TIFF_ASCII: + case TIFF_UNDEFINED: /* bit of a cheat... */ + /* + * Some vendors write strings w/o the trailing + * NULL byte, so always append one just in case. + */ + cp = (char *)_TIFFCheckMalloc(tif, dp->tdir_count + 1, + 1, mesg); + if( (ok = (cp && TIFFFetchString(tif, dp, cp))) != 0 ) + cp[dp->tdir_count] = '\0'; /* XXX */ + break; + } + if (ok) { + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, dp->tdir_count, cp) + : TIFFSetField(tif, dp->tdir_tag, cp)); + } + if (cp != NULL) + _TIFFfree(cp); + } else if (CheckDirCount(tif, dp, 1)) { /* singleton value */ + switch (dp->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + /* + * If the tag is also acceptable as a LONG or SLONG + * then TIFFSetField will expect an uint32 parameter + * passed to it (through varargs). Thus, for machines + * where sizeof (int) != sizeof (uint32) we must do + * a careful check here. It's hard to say if this + * is worth optimizing. + * + * NB: We use TIFFFieldWithTag here knowing that + * it returns us the first entry in the table + * for the tag and that that entry is for the + * widest potential data type the tag may have. + */ + { TIFFDataType type = fip->field_type; + if (type != TIFF_LONG && type != TIFF_SLONG) { + uint16 v = (uint16) + TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v) + : TIFFSetField(tif, dp->tdir_tag, v)); + break; + } + } + /* fall thru... */ + case TIFF_LONG: + case TIFF_SLONG: + { uint32 v32 = + TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v32) + : TIFFSetField(tif, dp->tdir_tag, v32)); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + { float v = (dp->tdir_type == TIFF_FLOAT ? + TIFFFetchFloat(tif, dp) + : TIFFFetchRational(tif, dp)); + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v) + : TIFFSetField(tif, dp->tdir_tag, v)); + } + break; + case TIFF_DOUBLE: + { double v; + ok = (TIFFFetchDoubleArray(tif, dp, &v) && + (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v) + : TIFFSetField(tif, dp->tdir_tag, v)) + ); + } + break; + case TIFF_ASCII: + case TIFF_UNDEFINED: /* bit of a cheat... */ + { char c[2]; + if( (ok = (TIFFFetchString(tif, dp, c) != 0)) != 0 ) { + c[1] = '\0'; /* XXX paranoid */ + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, c) + : TIFFSetField(tif, dp->tdir_tag, c)); + } + } + break; + } + } + return (ok); +} + +#define NITEMS(x) (sizeof (x) / sizeof (x[0])) +/* + * Fetch samples/pixel short values for + * the specified tag and verify that + * all values are the same. + */ +static int +TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, uint16* pl) +{ + uint16 samples = tif->tif_dir.td_samplesperpixel; + int status = 0; + + if (CheckDirCount(tif, dir, (uint32) samples)) { + uint16 buf[10]; + uint16* v = buf; + + if (dir->tdir_count > NITEMS(buf)) + v = (uint16*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof(uint16), + "to fetch per-sample values"); + if (v && TIFFFetchShortArray(tif, dir, v)) { + uint16 i; + int check_count = dir->tdir_count; + if( samples < check_count ) + check_count = samples; + + for (i = 1; i < check_count; i++) + if (v[i] != v[0]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Cannot handle different per-sample values for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + goto bad; + } + *pl = v[0]; + status = 1; + } + bad: + if (v && v != buf) + _TIFFfree(v); + } + return (status); +} + +/* + * Fetch samples/pixel long values for + * the specified tag and verify that + * all values are the same. + */ +static int +TIFFFetchPerSampleLongs(TIFF* tif, TIFFDirEntry* dir, uint32* pl) +{ + uint16 samples = tif->tif_dir.td_samplesperpixel; + int status = 0; + + if (CheckDirCount(tif, dir, (uint32) samples)) { + uint32 buf[10]; + uint32* v = buf; + + if (dir->tdir_count > NITEMS(buf)) + v = (uint32*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof(uint32), + "to fetch per-sample values"); + if (v && TIFFFetchLongArray(tif, dir, v)) { + uint16 i; + int check_count = dir->tdir_count; + + if( samples < check_count ) + check_count = samples; + for (i = 1; i < check_count; i++) + if (v[i] != v[0]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Cannot handle different per-sample values for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + goto bad; + } + *pl = v[0]; + status = 1; + } + bad: + if (v && v != buf) + _TIFFfree(v); + } + return (status); +} + +/* + * Fetch samples/pixel ANY values for the specified tag and verify that all + * values are the same. + */ +static int +TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl) +{ + uint16 samples = tif->tif_dir.td_samplesperpixel; + int status = 0; + + if (CheckDirCount(tif, dir, (uint32) samples)) { + double buf[10]; + double* v = buf; + + if (dir->tdir_count > NITEMS(buf)) + v = (double*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof (double), + "to fetch per-sample values"); + if (v && TIFFFetchAnyArray(tif, dir, v)) { + uint16 i; + int check_count = dir->tdir_count; + if( samples < check_count ) + check_count = samples; + + for (i = 1; i < check_count; i++) + if (v[i] != v[0]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Cannot handle different per-sample values for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + goto bad; + } + *pl = v[0]; + status = 1; + } + bad: + if (v && v != buf) + _TIFFfree(v); + } + return (status); +} +#undef NITEMS + +/* + * Fetch a set of offsets or lengths. + * While this routine says "strips", in fact it's also used for tiles. + */ +static int +TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, long nstrips, uint32** lpp) +{ + register uint32* lp; + int status; + + CheckDirCount(tif, dir, (uint32) nstrips); + + /* + * Allocate space for strip information. + */ + if (*lpp == NULL && + (*lpp = (uint32 *)_TIFFCheckMalloc(tif, + nstrips, sizeof (uint32), "for strip array")) == NULL) + return (0); + lp = *lpp; + _TIFFmemset( lp, 0, sizeof(uint32) * nstrips ); + + if (dir->tdir_type == (int)TIFF_SHORT) { + /* + * Handle uint16->uint32 expansion. + */ + uint16* dp = (uint16*) _TIFFCheckMalloc(tif, + dir->tdir_count, sizeof (uint16), "to fetch strip tag"); + if (dp == NULL) + return (0); + if( (status = TIFFFetchShortArray(tif, dir, dp)) != 0 ) { + int i; + + for( i = 0; i < nstrips && i < (int) dir->tdir_count; i++ ) + { + lp[i] = dp[i]; + } + } + _TIFFfree((char*) dp); + + } else if( nstrips != (int) dir->tdir_count ) { + /* Special case to correct length */ + + uint32* dp = (uint32*) _TIFFCheckMalloc(tif, + dir->tdir_count, sizeof (uint32), "to fetch strip tag"); + if (dp == NULL) + return (0); + + status = TIFFFetchLongArray(tif, dir, dp); + if( status != 0 ) { + int i; + + for( i = 0; i < nstrips && i < (int) dir->tdir_count; i++ ) + { + lp[i] = dp[i]; + } + } + + _TIFFfree( (char *) dp ); + } else + status = TIFFFetchLongArray(tif, dir, lp); + + return (status); +} + +/* + * Fetch and set the RefBlackWhite tag. + */ +static int +TIFFFetchRefBlackWhite(TIFF* tif, TIFFDirEntry* dir) +{ + static const char mesg[] = "for \"ReferenceBlackWhite\" array"; + char* cp; + int ok; + + if (dir->tdir_type == TIFF_RATIONAL) + return (TIFFFetchNormalTag(tif, dir)); + /* + * Handle LONG's for backward compatibility. + */ + cp = (char *)_TIFFCheckMalloc(tif, dir->tdir_count, + sizeof (uint32), mesg); + if( (ok = (cp && TIFFFetchLongArray(tif, dir, (uint32*) cp))) != 0) { + float* fp = (float*) + _TIFFCheckMalloc(tif, dir->tdir_count, sizeof (float), mesg); + if( (ok = (fp != NULL)) != 0 ) { + uint32 i; + for (i = 0; i < dir->tdir_count; i++) + fp[i] = (float)((uint32*) cp)[i]; + ok = TIFFSetField(tif, dir->tdir_tag, fp); + _TIFFfree((char*) fp); + } + } + if (cp) + _TIFFfree(cp); + return (ok); +} + +/* + * Fetch and set the SubjectDistance EXIF tag. + */ +static int +TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir) +{ + uint32 l[2]; + float v; + int ok = 0; + + if( dir->tdir_count != 1 || dir->tdir_type != TIFF_RATIONAL ) + { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count or type for SubjectDistance, tag ignored" ); + return (0); + } + + if (TIFFFetchData(tif, dir, (char *)l) + && cvtRational(tif, dir, l[0], l[1], &v)) { + /* + * XXX: Numerator 0xFFFFFFFF means that we have infinite + * distance. Indicate that with a negative floating point + * SubjectDistance value. + */ + ok = TIFFSetField(tif, dir->tdir_tag, + (l[0] != 0xFFFFFFFF) ? v : -v); + } + + return ok; +} + +/* + * Replace a single strip (tile) of uncompressed data by multiple strips + * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for + * dealing with large images or for dealing with machines with a limited + * amount memory. + */ +static void +ChopUpSingleUncompressedStrip(TIFF* tif) +{ + register TIFFDirectory *td = &tif->tif_dir; + uint32 bytecount = td->td_stripbytecount[0]; + uint32 offset = td->td_stripoffset[0]; + tsize_t rowbytes = TIFFVTileSize(tif, 1), stripbytes; + tstrip_t strip, nstrips, rowsperstrip; + uint32* newcounts; + uint32* newoffsets; + + /* + * Make the rows hold at least one scanline, but fill specified amount + * of data if possible. + */ + if (rowbytes > STRIP_SIZE_DEFAULT) { + stripbytes = rowbytes; + rowsperstrip = 1; + } else if (rowbytes > 0 ) { + rowsperstrip = STRIP_SIZE_DEFAULT / rowbytes; + stripbytes = rowbytes * rowsperstrip; + } + else + return; + + /* + * never increase the number of strips in an image + */ + if (rowsperstrip >= td->td_rowsperstrip) + return; + nstrips = (tstrip_t) TIFFhowmany(bytecount, stripbytes); + if( nstrips == 0 ) /* something is wonky, do nothing. */ + return; + + newcounts = (uint32*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint32), + "for chopped \"StripByteCounts\" array"); + newoffsets = (uint32*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint32), + "for chopped \"StripOffsets\" array"); + if (newcounts == NULL || newoffsets == NULL) { + /* + * Unable to allocate new strip information, give up and use + * the original one strip information. + */ + if (newcounts != NULL) + _TIFFfree(newcounts); + if (newoffsets != NULL) + _TIFFfree(newoffsets); + return; + } + /* + * Fill the strip information arrays with new bytecounts and offsets + * that reflect the broken-up format. + */ + for (strip = 0; strip < nstrips; strip++) { + if ((uint32)stripbytes > bytecount) + stripbytes = bytecount; + newcounts[strip] = stripbytes; + newoffsets[strip] = offset; + offset += stripbytes; + bytecount -= stripbytes; + } + /* + * Replace old single strip info with multi-strip info. + */ + td->td_stripsperimage = td->td_nstrips = nstrips; + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + + _TIFFfree(td->td_stripbytecount); + _TIFFfree(td->td_stripoffset); + td->td_stripbytecount = newcounts; + td->td_stripoffset = newoffsets; + td->td_stripbytecountsorted = 1; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_dirwrite.c b/thirdparty/libtiff/tif_dirwrite.c new file mode 100644 index 00000000..8d308c42 --- /dev/null +++ b/thirdparty/libtiff/tif_dirwrite.c @@ -0,0 +1,1414 @@ +/* $Id: tif_dirwrite.c,v 1.37.2.7 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Write Support Routines. + */ +#include "tiffiop.h" + +#ifdef HAVE_IEEEFP +# define TIFFCvtNativeToIEEEFloat(tif, n, fp) +# define TIFFCvtNativeToIEEEDouble(tif, n, dp) +#else +extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*); +extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*); +#endif + +static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*); +static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32); +static void TIFFSetupShort(TIFF*, ttag_t, TIFFDirEntry*, uint16); +static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*); +static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*); +static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*); +static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**); +static int TIFFWriteShortArray(TIFF*, TIFFDirEntry*, uint16*); +static int TIFFWriteLongArray(TIFF *, TIFFDirEntry*, uint32*); +static int TIFFWriteRationalArray(TIFF *, TIFFDirEntry*, float*); +static int TIFFWriteFloatArray(TIFF *, TIFFDirEntry*, float*); +static int TIFFWriteDoubleArray(TIFF *, TIFFDirEntry*, double*); +static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*); +static int TIFFWriteAnyArray(TIFF*, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*); +static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*); +static int TIFFWriteInkNames(TIFF*, TIFFDirEntry*); +static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*); +static int TIFFLinkDirectory(TIFF*); + +#define WriteRationalPair(type, tag1, v1, tag2, v2) { \ + TIFFWriteRational((tif), (type), (tag1), (dir), (v1)) \ + TIFFWriteRational((tif), (type), (tag2), (dir)+1, (v2)) \ + (dir)++; \ +} +#define TIFFWriteRational(tif, type, tag, dir, v) \ + (dir)->tdir_tag = (tag); \ + (dir)->tdir_type = (type); \ + (dir)->tdir_count = 1; \ + if (!TIFFWriteRationalArray((tif), (dir), &(v))) \ + goto bad; + +/* + * Write the contents of the current directory + * to the specified file. This routine doesn't + * handle overwriting a directory with auxiliary + * storage that's been changed. + */ +static int +_TIFFWriteDirectory(TIFF* tif, int done) +{ + uint16 dircount; + toff_t diroff; + ttag_t tag; + uint32 nfields; + tsize_t dirsize; + char* data; + TIFFDirEntry* dir; + TIFFDirectory* td; + unsigned long b, fields[FIELD_SETLONGS]; + int fi, nfi; + + if (tif->tif_mode == O_RDONLY) + return (1); + /* + * Clear write state so that subsequent images with + * different characteristics get the right buffers + * setup for them. + */ + if (done) + { + if (tif->tif_flags & TIFF_POSTENCODE) { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) { + TIFFErrorExt(tif->tif_clientdata, + tif->tif_name, + "Error post-encoding before directory write"); + return (0); + } + } + (*tif->tif_close)(tif); /* shutdown encoder */ + /* + * Flush any data that might have been written + * by the compression close+cleanup routines. + */ + if (tif->tif_rawcc > 0 + && (tif->tif_flags & TIFF_BEENWRITING) != 0 + && !TIFFFlushData1(tif)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error flushing data before directory write"); + return (0); + } + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + tif->tif_rawdatasize = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); + } + + td = &tif->tif_dir; + /* + * Size the directory so that we can calculate + * offsets for the data items that aren't kept + * in-place in each field. + */ + nfields = 0; + for (b = 0; b <= FIELD_LAST; b++) + if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) + nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); + nfields += td->td_customValueCount; + dirsize = nfields * sizeof (TIFFDirEntry); + data = (char*) _TIFFmalloc(dirsize); + if (data == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Cannot write directory, out of space"); + return (0); + } + /* + * Directory hasn't been placed yet, put + * it at the end of the file and link it + * into the existing directory structure. + */ + if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) + goto bad; + tif->tif_dataoff = (toff_t)( + tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); + if (tif->tif_dataoff & 1) + tif->tif_dataoff++; + (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); + tif->tif_curdir++; + dir = (TIFFDirEntry*) data; + /* + * Setup external form of directory + * entries and write data items. + */ + _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); + /* + * Write out ExtraSamples tag only if + * extra samples are present in the data. + */ + if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { + ResetFieldBit(fields, FIELD_EXTRASAMPLES); + nfields--; + dirsize -= sizeof (TIFFDirEntry); + } /*XXX*/ + for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { + const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; + + /* + * For custom fields, we test to see if the custom field + * is set or not. For normal fields, we just use the + * FieldSet test. + */ + if( fip->field_bit == FIELD_CUSTOM ) + { + int ci, is_set = FALSE; + + for( ci = 0; ci < td->td_customValueCount; ci++ ) + is_set |= (td->td_customValues[ci].info == fip); + + if( !is_set ) + continue; + } + else if (!FieldSet(fields, fip->field_bit)) + continue; + + /* + * Handle other fields. + */ + switch (fip->field_bit) + { + case FIELD_STRIPOFFSETS: + /* + * We use one field bit for both strip and tile + + * offsets, and so must be careful in selecting + * the appropriate field descriptor (so that tags + * are written in sorted order). + */ + tag = isTiled(tif) ? + TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS; + if (tag != fip->field_tag) + continue; + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (uint16) TIFF_LONG; + dir->tdir_count = (uint32) td->td_nstrips; + if (!TIFFWriteLongArray(tif, dir, td->td_stripoffset)) + goto bad; + break; + case FIELD_STRIPBYTECOUNTS: + /* + * We use one field bit for both strip and tile + * byte counts, and so must be careful in selecting + * the appropriate field descriptor (so that tags + * are written in sorted order). + */ + tag = isTiled(tif) ? + TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS; + if (tag != fip->field_tag) + continue; + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (uint16) TIFF_LONG; + dir->tdir_count = (uint32) td->td_nstrips; + if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount)) + goto bad; + break; + case FIELD_ROWSPERSTRIP: + TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, + dir, td->td_rowsperstrip); + break; + case FIELD_COLORMAP: + if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, + 3, td->td_colormap)) + goto bad; + break; + case FIELD_IMAGEDIMENSIONS: + TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, + dir++, td->td_imagewidth); + TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, + dir, td->td_imagelength); + break; + case FIELD_TILEDIMENSIONS: + TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, + dir++, td->td_tilewidth); + TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, + dir, td->td_tilelength); + break; + case FIELD_COMPRESSION: + TIFFSetupShort(tif, TIFFTAG_COMPRESSION, + dir, td->td_compression); + break; + case FIELD_PHOTOMETRIC: + TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, + dir, td->td_photometric); + break; + case FIELD_POSITION: + WriteRationalPair(TIFF_RATIONAL, + TIFFTAG_XPOSITION, td->td_xposition, + TIFFTAG_YPOSITION, td->td_yposition); + break; + case FIELD_RESOLUTION: + WriteRationalPair(TIFF_RATIONAL, + TIFFTAG_XRESOLUTION, td->td_xresolution, + TIFFTAG_YRESOLUTION, td->td_yresolution); + break; + case FIELD_BITSPERSAMPLE: + case FIELD_MINSAMPLEVALUE: + case FIELD_MAXSAMPLEVALUE: + case FIELD_SAMPLEFORMAT: + if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) + goto bad; + break; + case FIELD_SMINSAMPLEVALUE: + case FIELD_SMAXSAMPLEVALUE: + if (!TIFFWritePerSampleAnys(tif, + _TIFFSampleToTagType(tif), fip->field_tag, dir)) + goto bad; + break; + case FIELD_PAGENUMBER: + case FIELD_HALFTONEHINTS: + case FIELD_YCBCRSUBSAMPLING: + if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) + goto bad; + break; + case FIELD_INKNAMES: + if (!TIFFWriteInkNames(tif, dir)) + goto bad; + break; + case FIELD_TRANSFERFUNCTION: + if (!TIFFWriteTransferFunction(tif, dir)) + goto bad; + break; + case FIELD_SUBIFD: + /* + * XXX: Always write this field using LONG type + * for backward compatibility. + */ + dir->tdir_tag = (uint16) fip->field_tag; + dir->tdir_type = (uint16) TIFF_LONG; + dir->tdir_count = (uint32) td->td_nsubifd; + if (!TIFFWriteLongArray(tif, dir, td->td_subifd)) + goto bad; + /* + * Total hack: if this directory includes a SubIFD + * tag then force the next directories to be + * written as ``sub directories'' of this one. This + * is used to write things like thumbnails and + * image masks that one wants to keep out of the + * normal directory linkage access mechanism. + */ + if (dir->tdir_count > 0) { + tif->tif_flags |= TIFF_INSUBIFD; + tif->tif_nsubifd = (uint16) dir->tdir_count; + if (dir->tdir_count > 1) + tif->tif_subifdoff = dir->tdir_offset; + else + tif->tif_subifdoff = (uint32)( + tif->tif_diroff + + sizeof (uint16) + + ((char*)&dir->tdir_offset-data)); + } + break; + default: + /* XXX: Should be fixed and removed. */ + if (fip->field_tag == TIFFTAG_DOTRANGE) { + if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) + goto bad; + } + else if (!TIFFWriteNormalTag(tif, dir, fip)) + goto bad; + break; + } + dir++; + + if( fip->field_bit != FIELD_CUSTOM ) + ResetFieldBit(fields, fip->field_bit); + } + + /* + * Write directory. + */ + dircount = (uint16) nfields; + diroff = (uint32) tif->tif_nextdiroff; + if (tif->tif_flags & TIFF_SWAB) { + /* + * The file's byte order is opposite to the + * native machine architecture. We overwrite + * the directory information with impunity + * because it'll be released below after we + * write it to the file. Note that all the + * other tag construction routines assume that + * we do this byte-swapping; i.e. they only + * byte-swap indirect data. + */ + for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { + TIFFSwabArrayOfShort(&dir->tdir_tag, 2); + TIFFSwabArrayOfLong(&dir->tdir_count, 2); + } + dircount = (uint16) nfields; + TIFFSwabShort(&dircount); + TIFFSwabLong(&diroff); + } + (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); + if (!WriteOK(tif, &dircount, sizeof (dircount))) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing directory count"); + goto bad; + } + if (!WriteOK(tif, data, dirsize)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing directory contents"); + goto bad; + } + if (!WriteOK(tif, &diroff, sizeof (uint32))) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing directory link"); + goto bad; + } + if (done) { + TIFFFreeDirectory(tif); + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + (*tif->tif_cleanup)(tif); + + /* + * Reset directory-related state for subsequent + * directories. + */ + TIFFCreateDirectory(tif); + } + _TIFFfree(data); + return (1); +bad: + _TIFFfree(data); + return (0); +} +#undef WriteRationalPair + +int +TIFFWriteDirectory(TIFF* tif) +{ + return _TIFFWriteDirectory(tif, TRUE); +} + +/* + * Similar to TIFFWriteDirectory(), writes the directory out + * but leaves all data structures in memory so that it can be + * written again. This will make a partially written TIFF file + * readable before it is successfully completed/closed. + */ +int +TIFFCheckpointDirectory(TIFF* tif) +{ + int rc; + /* Setup the strips arrays, if they haven't already been. */ + if (tif->tif_dir.td_stripoffset == NULL) + (void) TIFFSetupStrips(tif); + rc = _TIFFWriteDirectory(tif, FALSE); + (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END)); + return rc; +} + +static int +_TIFFWriteCustomDirectory(TIFF* tif, toff_t *pdiroff) +{ + uint16 dircount; + uint32 nfields; + tsize_t dirsize; + char* data; + TIFFDirEntry* dir; + TIFFDirectory* td; + unsigned long b, fields[FIELD_SETLONGS]; + int fi, nfi; + + if (tif->tif_mode == O_RDONLY) + return (1); + + td = &tif->tif_dir; + /* + * Size the directory so that we can calculate + * offsets for the data items that aren't kept + * in-place in each field. + */ + nfields = 0; + for (b = 0; b <= FIELD_LAST; b++) + if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) + nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); + nfields += td->td_customValueCount; + dirsize = nfields * sizeof (TIFFDirEntry); + data = (char*) _TIFFmalloc(dirsize); + if (data == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Cannot write directory, out of space"); + return (0); + } + /* + * Put the directory at the end of the file. + */ + tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1; + tif->tif_dataoff = (toff_t)( + tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); + if (tif->tif_dataoff & 1) + tif->tif_dataoff++; + (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); + dir = (TIFFDirEntry*) data; + /* + * Setup external form of directory + * entries and write data items. + */ + _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); + + for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { + const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; + + /* + * For custom fields, we test to see if the custom field + * is set or not. For normal fields, we just use the + * FieldSet test. + */ + if( fip->field_bit == FIELD_CUSTOM ) + { + int ci, is_set = FALSE; + + for( ci = 0; ci < td->td_customValueCount; ci++ ) + is_set |= (td->td_customValues[ci].info == fip); + + if( !is_set ) + continue; + } + else if (!FieldSet(fields, fip->field_bit)) + continue; + + if( fip->field_bit != FIELD_CUSTOM ) + ResetFieldBit(fields, fip->field_bit); + } + + /* + * Write directory. + */ + dircount = (uint16) nfields; + *pdiroff = (uint32) tif->tif_nextdiroff; + if (tif->tif_flags & TIFF_SWAB) { + /* + * The file's byte order is opposite to the + * native machine architecture. We overwrite + * the directory information with impunity + * because it'll be released below after we + * write it to the file. Note that all the + * other tag construction routines assume that + * we do this byte-swapping; i.e. they only + * byte-swap indirect data. + */ + for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { + TIFFSwabArrayOfShort(&dir->tdir_tag, 2); + TIFFSwabArrayOfLong(&dir->tdir_count, 2); + } + dircount = (uint16) nfields; + TIFFSwabShort(&dircount); + TIFFSwabLong(pdiroff); + } + (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); + if (!WriteOK(tif, &dircount, sizeof (dircount))) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing directory count"); + goto bad; + } + if (!WriteOK(tif, data, dirsize)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing directory contents"); + goto bad; + } + if (!WriteOK(tif, pdiroff, sizeof (uint32))) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing directory link"); + goto bad; + } + _TIFFfree(data); + return (1); +bad: + _TIFFfree(data); + return (0); +} + +int +TIFFWriteCustomDirectory(TIFF* tif, toff_t *pdiroff) +{ + return _TIFFWriteCustomDirectory(tif, pdiroff); +} + +/* + * Process tags that are not special cased. + */ +static int +TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip) +{ + uint16 wc = (uint16) fip->field_writecount; + uint32 wc2; + + dir->tdir_tag = (uint16) fip->field_tag; + dir->tdir_type = (uint16) fip->field_type; + dir->tdir_count = wc; + + switch (fip->field_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + if (fip->field_passcount) { + uint16* wp; + if (wc == (uint16) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &wp); + dir->tdir_count = wc2; + } else { /* Assume TIFF_VARIABLE */ + TIFFGetField(tif, fip->field_tag, &wc, &wp); + dir->tdir_count = wc; + } + if (!TIFFWriteShortArray(tif, dir, wp)) + return 0; + } else { + if (wc == 1) { + uint16 sv; + TIFFGetField(tif, fip->field_tag, &sv); + dir->tdir_offset = + TIFFInsertData(tif, dir->tdir_type, sv); + } else { + uint16* wp; + TIFFGetField(tif, fip->field_tag, &wp); + if (!TIFFWriteShortArray(tif, dir, wp)) + return 0; + } + } + break; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_IFD: + if (fip->field_passcount) { + uint32* lp; + if (wc == (uint16) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &lp); + dir->tdir_count = wc2; + } else { /* Assume TIFF_VARIABLE */ + TIFFGetField(tif, fip->field_tag, &wc, &lp); + dir->tdir_count = wc; + } + if (!TIFFWriteLongArray(tif, dir, lp)) + return 0; + } else { + if (wc == 1) { + /* XXX handle LONG->SHORT conversion */ + TIFFGetField(tif, fip->field_tag, + &dir->tdir_offset); + } else { + uint32* lp; + TIFFGetField(tif, fip->field_tag, &lp); + if (!TIFFWriteLongArray(tif, dir, lp)) + return 0; + } + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + if (fip->field_passcount) { + float* fp; + if (wc == (uint16) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &fp); + dir->tdir_count = wc2; + } else { /* Assume TIFF_VARIABLE */ + TIFFGetField(tif, fip->field_tag, &wc, &fp); + dir->tdir_count = wc; + } + if (!TIFFWriteRationalArray(tif, dir, fp)) + return 0; + } else { + if (wc == 1) { + float fv; + TIFFGetField(tif, fip->field_tag, &fv); + if (!TIFFWriteRationalArray(tif, dir, &fv)) + return 0; + } else { + float* fp; + TIFFGetField(tif, fip->field_tag, &fp); + if (!TIFFWriteRationalArray(tif, dir, fp)) + return 0; + } + } + break; + case TIFF_FLOAT: + if (fip->field_passcount) { + float* fp; + if (wc == (uint16) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &fp); + dir->tdir_count = wc2; + } else { /* Assume TIFF_VARIABLE */ + TIFFGetField(tif, fip->field_tag, &wc, &fp); + dir->tdir_count = wc; + } + if (!TIFFWriteFloatArray(tif, dir, fp)) + return 0; + } else { + if (wc == 1) { + float fv; + TIFFGetField(tif, fip->field_tag, &fv); + if (!TIFFWriteFloatArray(tif, dir, &fv)) + return 0; + } else { + float* fp; + TIFFGetField(tif, fip->field_tag, &fp); + if (!TIFFWriteFloatArray(tif, dir, fp)) + return 0; + } + } + break; + case TIFF_DOUBLE: + if (fip->field_passcount) { + double* dp; + if (wc == (uint16) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &dp); + dir->tdir_count = wc2; + } else { /* Assume TIFF_VARIABLE */ + TIFFGetField(tif, fip->field_tag, &wc, &dp); + dir->tdir_count = wc; + } + if (!TIFFWriteDoubleArray(tif, dir, dp)) + return 0; + } else { + if (wc == 1) { + double dv; + TIFFGetField(tif, fip->field_tag, &dv); + if (!TIFFWriteDoubleArray(tif, dir, &dv)) + return 0; + } else { + double* dp; + TIFFGetField(tif, fip->field_tag, &dp); + if (!TIFFWriteDoubleArray(tif, dir, dp)) + return 0; + } + } + break; + case TIFF_ASCII: + { + char* cp; + if (fip->field_passcount) + { + if( wc == (uint16) TIFF_VARIABLE2 ) + TIFFGetField(tif, fip->field_tag, &wc2, &cp); + else + TIFFGetField(tif, fip->field_tag, &wc, &cp); + } + else + TIFFGetField(tif, fip->field_tag, &cp); + + dir->tdir_count = (uint32) (strlen(cp) + 1); + if (!TIFFWriteByteArray(tif, dir, cp)) + return (0); + } + break; + + case TIFF_BYTE: + case TIFF_SBYTE: + if (fip->field_passcount) { + char* cp; + if (wc == (uint16) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &cp); + dir->tdir_count = wc2; + } else { /* Assume TIFF_VARIABLE */ + TIFFGetField(tif, fip->field_tag, &wc, &cp); + dir->tdir_count = wc; + } + if (!TIFFWriteByteArray(tif, dir, cp)) + return 0; + } else { + if (wc == 1) { + char cv; + TIFFGetField(tif, fip->field_tag, &cv); + if (!TIFFWriteByteArray(tif, dir, &cv)) + return 0; + } else { + char* cp; + TIFFGetField(tif, fip->field_tag, &cp); + if (!TIFFWriteByteArray(tif, dir, cp)) + return 0; + } + } + break; + + case TIFF_UNDEFINED: + { char* cp; + if (wc == (unsigned short) TIFF_VARIABLE) { + TIFFGetField(tif, fip->field_tag, &wc, &cp); + dir->tdir_count = wc; + } else if (wc == (unsigned short) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &cp); + dir->tdir_count = wc2; + } else + TIFFGetField(tif, fip->field_tag, &cp); + if (!TIFFWriteByteArray(tif, dir, cp)) + return (0); + } + break; + + case TIFF_NOTYPE: + break; + } + return (1); +} + +/* + * Setup a directory entry with either a SHORT + * or LONG type according to the value. + */ +static void +TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_count = 1; + if (v > 0xffffL) { + dir->tdir_type = (short) TIFF_LONG; + dir->tdir_offset = v; + } else { + dir->tdir_type = (short) TIFF_SHORT; + dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v); + } +} + +/* + * Setup a SHORT directory entry + */ +static void +TIFFSetupShort(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint16 v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_count = 1; + dir->tdir_type = (short) TIFF_SHORT; + dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v); +} +#undef MakeShortDirent + +#define NITEMS(x) (sizeof (x) / sizeof (x[0])) +/* + * Setup a directory entry that references a + * samples/pixel array of SHORT values and + * (potentially) write the associated indirect + * values. + */ +static int +TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) +{ + uint16 buf[10], v; + uint16* w = buf; + uint16 i, samples = tif->tif_dir.td_samplesperpixel; + int status; + + if (samples > NITEMS(buf)) { + w = (uint16*) _TIFFmalloc(samples * sizeof (uint16)); + if (w == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "No space to write per-sample shorts"); + return (0); + } + } + TIFFGetField(tif, tag, &v); + for (i = 0; i < samples; i++) + w[i] = v; + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (uint16) TIFF_SHORT; + dir->tdir_count = samples; + status = TIFFWriteShortArray(tif, dir, w); + if (w != buf) + _TIFFfree((char*) w); + return (status); +} + +/* + * Setup a directory entry that references a samples/pixel array of ``type'' + * values and (potentially) write the associated indirect values. The source + * data from TIFFGetField() for the specified tag must be returned as double. + */ +static int +TIFFWritePerSampleAnys(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir) +{ + double buf[10], v; + double* w = buf; + uint16 i, samples = tif->tif_dir.td_samplesperpixel; + int status; + + if (samples > NITEMS(buf)) { + w = (double*) _TIFFmalloc(samples * sizeof (double)); + if (w == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "No space to write per-sample values"); + return (0); + } + } + TIFFGetField(tif, tag, &v); + for (i = 0; i < samples; i++) + w[i] = v; + status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w); + if (w != buf) + _TIFFfree(w); + return (status); +} +#undef NITEMS + +/* + * Setup a pair of shorts that are returned by + * value, rather than as a reference to an array. + */ +static int +TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) +{ + uint16 v[2]; + + TIFFGetField(tif, tag, &v[0], &v[1]); + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (uint16) TIFF_SHORT; + dir->tdir_count = 2; + return (TIFFWriteShortArray(tif, dir, v)); +} + +/* + * Setup a directory entry for an NxM table of shorts, + * where M is known to be 2**bitspersample, and write + * the associated indirect data. + */ +static int +TIFFWriteShortTable(TIFF* tif, + ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table) +{ + uint32 i, off; + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) TIFF_SHORT; + /* XXX -- yech, fool TIFFWriteData */ + dir->tdir_count = (uint32) (1L<tif_dir.td_bitspersample); + off = tif->tif_dataoff; + for (i = 0; i < n; i++) + if (!TIFFWriteData(tif, dir, (char *)table[i])) + return (0); + dir->tdir_count *= n; + dir->tdir_offset = off; + return (1); +} + +/* + * Write/copy data associated with an ASCII or opaque tag value. + */ +static int +TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + if (dir->tdir_count <= 4) { + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + dir->tdir_offset = (uint32)cp[0] << 24; + if (dir->tdir_count >= 2) + dir->tdir_offset |= (uint32)cp[1] << 16; + if (dir->tdir_count >= 3) + dir->tdir_offset |= (uint32)cp[2] << 8; + if (dir->tdir_count == 4) + dir->tdir_offset |= cp[3]; + } else { + dir->tdir_offset = cp[0]; + if (dir->tdir_count >= 2) + dir->tdir_offset |= (uint32) cp[1] << 8; + if (dir->tdir_count >= 3) + dir->tdir_offset |= (uint32) cp[2] << 16; + if (dir->tdir_count == 4) + dir->tdir_offset |= (uint32) cp[3] << 24; + } + return 1; + } else + return TIFFWriteData(tif, dir, cp); +} + +/* + * Setup a directory entry of an array of SHORT + * or SSHORT and write the associated indirect values. + */ +static int +TIFFWriteShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v) +{ + if (dir->tdir_count <= 2) { + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + dir->tdir_offset = (uint32) v[0] << 16; + if (dir->tdir_count == 2) + dir->tdir_offset |= v[1] & 0xffff; + } else { + dir->tdir_offset = v[0] & 0xffff; + if (dir->tdir_count == 2) + dir->tdir_offset |= (uint32) v[1] << 16; + } + return (1); + } else + return (TIFFWriteData(tif, dir, (char*) v)); +} + +/* + * Setup a directory entry of an array of LONG + * or SLONG and write the associated indirect values. + */ +static int +TIFFWriteLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v) +{ + if (dir->tdir_count == 1) { + dir->tdir_offset = v[0]; + return (1); + } else + return (TIFFWriteData(tif, dir, (char*) v)); +} + +/* + * Setup a directory entry of an array of RATIONAL + * or SRATIONAL and write the associated indirect values. + */ +static int +TIFFWriteRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v) +{ + uint32 i; + uint32* t; + int status; + + t = (uint32*) _TIFFmalloc(2 * dir->tdir_count * sizeof (uint32)); + if (t == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "No space to write RATIONAL array"); + return (0); + } + for (i = 0; i < dir->tdir_count; i++) { + float fv = v[i]; + int sign = 1; + uint32 den; + + if (fv < 0) { + if (dir->tdir_type == TIFF_RATIONAL) { + TIFFWarningExt(tif->tif_clientdata, + tif->tif_name, + "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL", + _TIFFFieldWithTag(tif,dir->tdir_tag)->field_name, + fv); + fv = 0; + } else + fv = -fv, sign = -1; + } + den = 1L; + if (fv > 0) { + while (fv < 1L<<(31-3) && den < 1L<<(31-3)) + fv *= 1<<3, den *= 1L<<3; + } + t[2*i+0] = (uint32) (sign * (fv + 0.5)); + t[2*i+1] = den; + } + status = TIFFWriteData(tif, dir, (char *)t); + _TIFFfree((char*) t); + return (status); +} + +static int +TIFFWriteFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v) +{ + TIFFCvtNativeToIEEEFloat(tif, dir->tdir_count, v); + if (dir->tdir_count == 1) { + dir->tdir_offset = *(uint32*) &v[0]; + return (1); + } else + return (TIFFWriteData(tif, dir, (char*) v)); +} + +static int +TIFFWriteDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v) +{ + TIFFCvtNativeToIEEEDouble(tif, dir->tdir_count, v); + return (TIFFWriteData(tif, dir, (char*) v)); +} + +/* + * Write an array of ``type'' values for a specified tag (i.e. this is a tag + * which is allowed to have different types, e.g. SMaxSampleType). + * Internally the data values are represented as double since a double can + * hold any of the TIFF tag types (yes, this should really be an abstract + * type tany_t for portability). The data is converted into the specified + * type in a temporary buffer and then handed off to the appropriate array + * writer. + */ +static int +TIFFWriteAnyArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v) +{ + char buf[10 * sizeof(double)]; + char* w = buf; + int i, status = 0; + + if (n * TIFFDataWidth(type) > sizeof buf) { + w = (char*) _TIFFmalloc(n * TIFFDataWidth(type)); + if (w == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "No space to write array"); + return (0); + } + } + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (uint16) type; + dir->tdir_count = n; + + switch (type) { + case TIFF_BYTE: + { + uint8* bp = (uint8*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (uint8) v[i]; + if (!TIFFWriteByteArray(tif, dir, (char*) bp)) + goto out; + } + break; + case TIFF_SBYTE: + { + int8* bp = (int8*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (int8) v[i]; + if (!TIFFWriteByteArray(tif, dir, (char*) bp)) + goto out; + } + break; + case TIFF_SHORT: + { + uint16* bp = (uint16*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (uint16) v[i]; + if (!TIFFWriteShortArray(tif, dir, (uint16*)bp)) + goto out; + } + break; + case TIFF_SSHORT: + { + int16* bp = (int16*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (int16) v[i]; + if (!TIFFWriteShortArray(tif, dir, (uint16*)bp)) + goto out; + } + break; + case TIFF_LONG: + { + uint32* bp = (uint32*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (uint32) v[i]; + if (!TIFFWriteLongArray(tif, dir, bp)) + goto out; + } + break; + case TIFF_SLONG: + { + int32* bp = (int32*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (int32) v[i]; + if (!TIFFWriteLongArray(tif, dir, (uint32*) bp)) + goto out; + } + break; + case TIFF_FLOAT: + { + float* bp = (float*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (float) v[i]; + if (!TIFFWriteFloatArray(tif, dir, bp)) + goto out; + } + break; + case TIFF_DOUBLE: + { + if( !TIFFWriteDoubleArray(tif, dir, v)) + goto out; + } + break; + default: + /* TIFF_NOTYPE */ + /* TIFF_ASCII */ + /* TIFF_UNDEFINED */ + /* TIFF_RATIONAL */ + /* TIFF_SRATIONAL */ + goto out; + } + status = 1; + out: + if (w != buf) + _TIFFfree(w); + return (status); +} + +static int +TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir) +{ + TIFFDirectory* td = &tif->tif_dir; + tsize_t n = (1L<td_bitspersample) * sizeof (uint16); + uint16** tf = td->td_transferfunction; + int ncols; + + /* + * Check if the table can be written as a single column, + * or if it must be written as 3 columns. Note that we + * write a 3-column tag if there are 2 samples/pixel and + * a single column of data won't suffice--hmm. + */ + switch (td->td_samplesperpixel - td->td_extrasamples) { + default: if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; } + case 2: if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; } + case 1: case 0: ncols = 1; + } + return (TIFFWriteShortTable(tif, + TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf)); +} + +static int +TIFFWriteInkNames(TIFF* tif, TIFFDirEntry* dir) +{ + TIFFDirectory* td = &tif->tif_dir; + + dir->tdir_tag = TIFFTAG_INKNAMES; + dir->tdir_type = (short) TIFF_ASCII; + dir->tdir_count = td->td_inknameslen; + return (TIFFWriteByteArray(tif, dir, td->td_inknames)); +} + +/* + * Write a contiguous directory item. + */ +static int +TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + tsize_t cc; + + if (tif->tif_flags & TIFF_SWAB) { + switch (dir->tdir_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); + break; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); + break; + case TIFF_DOUBLE: + TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); + break; + } + } + dir->tdir_offset = tif->tif_dataoff; + cc = dir->tdir_count * TIFFDataWidth((TIFFDataType) dir->tdir_type); + if (SeekOK(tif, dir->tdir_offset) && + WriteOK(tif, cp, cc)) { + tif->tif_dataoff += (cc + 1) & ~1; + return (1); + } + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing data for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + return (0); +} + +/* + * Similar to TIFFWriteDirectory(), but if the directory has already + * been written once, it is relocated to the end of the file, in case it + * has changed in size. Note that this will result in the loss of the + * previously used directory space. + */ + +int +TIFFRewriteDirectory( TIFF *tif ) +{ + static const char module[] = "TIFFRewriteDirectory"; + + /* We don't need to do anything special if it hasn't been written. */ + if( tif->tif_diroff == 0 ) + return TIFFWriteDirectory( tif ); + + /* + ** Find and zero the pointer to this directory, so that TIFFLinkDirectory + ** will cause it to be added after this directories current pre-link. + */ + + /* Is it the first directory in the file? */ + if (tif->tif_header.tiff_diroff == tif->tif_diroff) + { + tif->tif_header.tiff_diroff = 0; + tif->tif_diroff = 0; + + TIFFSeekFile(tif, (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE), + SEEK_SET); + if (!WriteOK(tif, &(tif->tif_header.tiff_diroff), + sizeof (tif->tif_diroff))) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error updating TIFF header"); + return (0); + } + } + else + { + toff_t nextdir, off; + + nextdir = tif->tif_header.tiff_diroff; + do { + uint16 dircount; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, sizeof (dircount))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + dircount * sizeof (TIFFDirEntry), SEEK_CUR); + if (!ReadOK(tif, &nextdir, sizeof (nextdir))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir); + } while (nextdir != tif->tif_diroff && nextdir != 0); + off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */ + (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET); + tif->tif_diroff = 0; + if (!WriteOK(tif, &(tif->tif_diroff), sizeof (nextdir))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + } + + /* + ** Now use TIFFWriteDirectory() normally. + */ + + return TIFFWriteDirectory( tif ); +} + + +/* + * Link the current directory into the directory chain for the file. + */ +static int +TIFFLinkDirectory(TIFF* tif) +{ + static const char module[] = "TIFFLinkDirectory"; + toff_t nextdir; + toff_t diroff, off; + + tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1; + diroff = tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&diroff); + + /* + * Handle SubIFDs + */ + if (tif->tif_flags & TIFF_INSUBIFD) { + (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Error writing SubIFD directory link", + tif->tif_name); + return (0); + } + /* + * Advance to the next SubIFD or, if this is + * the last one configured, revert back to the + * normal directory linkage. + */ + if (--tif->tif_nsubifd) + tif->tif_subifdoff += sizeof (diroff); + else + tif->tif_flags &= ~TIFF_INSUBIFD; + return (1); + } + + if (tif->tif_header.tiff_diroff == 0) { + /* + * First directory, overwrite offset in header. + */ + tif->tif_header.tiff_diroff = tif->tif_diroff; + (void) TIFFSeekFile(tif, + (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE), + SEEK_SET); + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + nextdir = tif->tif_header.tiff_diroff; + do { + uint16 dircount; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, sizeof (dircount))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + dircount * sizeof (TIFFDirEntry), SEEK_CUR); + if (!ReadOK(tif, &nextdir, sizeof (nextdir))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir); + } while (nextdir != 0); + off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */ + (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET); + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + return (1); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_dumpmode.c b/thirdparty/libtiff/tif_dumpmode.c new file mode 100644 index 00000000..da861503 --- /dev/null +++ b/thirdparty/libtiff/tif_dumpmode.c @@ -0,0 +1,126 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dumpmode.c,v 1.5.2.2 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * "Null" Compression Algorithm Support. + */ +#include "tiffiop.h" + +/* + * Encode a hunk of pixels. + */ +static int +DumpModeEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) s; + while (cc > 0) { + tsize_t n; + + n = cc; + if (tif->tif_rawcc + n > tif->tif_rawdatasize) + n = tif->tif_rawdatasize - tif->tif_rawcc; + + assert( n > 0 ); + + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != pp) + _TIFFmemcpy(tif->tif_rawcp, pp, n); + tif->tif_rawcp += n; + tif->tif_rawcc += n; + pp += n; + cc -= n; + if (tif->tif_rawcc >= tif->tif_rawdatasize && + !TIFFFlushData1(tif)) + return (-1); + } + return (1); +} + +/* + * Decode a hunk of pixels. + */ +static int +DumpModeDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + (void) s; +/* fprintf(stderr,"DumpModeDecode: scanline %ld, expected %ld bytes, got %ld bytes\n", */ +/* (long) tif->tif_row, (long) tif->tif_rawcc, (long) cc); */ + if (tif->tif_rawcc < cc) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "DumpModeDecode: Not enough data for scanline %d", + tif->tif_row); + return (0); + } + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != buf) + _TIFFmemcpy(buf, tif->tif_rawcp, cc); + tif->tif_rawcp += cc; + tif->tif_rawcc -= cc; + return (1); +} + +/* + * Seek forwards nrows in the current strip. + */ +static int +DumpModeSeek(TIFF* tif, uint32 nrows) +{ + tif->tif_rawcp += nrows * tif->tif_scanlinesize; + tif->tif_rawcc -= nrows * tif->tif_scanlinesize; + return (1); +} + +/* + * Initialize dump mode. + */ +int +TIFFInitDumpMode(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = DumpModeDecode; + tif->tif_decodestrip = DumpModeDecode; + tif->tif_decodetile = DumpModeDecode; + tif->tif_encoderow = DumpModeEncode; + tif->tif_encodestrip = DumpModeEncode; + tif->tif_encodetile = DumpModeEncode; + tif->tif_seek = DumpModeSeek; + return (1); +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_error.c b/thirdparty/libtiff/tif_error.c new file mode 100644 index 00000000..2377abda --- /dev/null +++ b/thirdparty/libtiff/tif_error.c @@ -0,0 +1,80 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_error.c,v 1.4.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL; + +TIFFErrorHandler +TIFFSetErrorHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFerrorHandler; + _TIFFerrorHandler = handler; + return (prev); +} + +TIFFErrorHandlerExt +TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler) +{ + TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt; + _TIFFerrorHandlerExt = handler; + return (prev); +} + +void +TIFFError(const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFerrorHandler) + (*_TIFFerrorHandler)(module, fmt, ap); + if (_TIFFerrorHandlerExt) + (*_TIFFerrorHandlerExt)(0, module, fmt, ap); + va_end(ap); +} + +void +TIFFErrorExt(thandle_t fd, const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFerrorHandler) + (*_TIFFerrorHandler)(module, fmt, ap); + if (_TIFFerrorHandlerExt) + (*_TIFFerrorHandlerExt)(fd, module, fmt, ap); + va_end(ap); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_extension.c b/thirdparty/libtiff/tif_extension.c new file mode 100644 index 00000000..b67c0f00 --- /dev/null +++ b/thirdparty/libtiff/tif_extension.c @@ -0,0 +1,118 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_extension.c,v 1.4.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Various routines support external extension of the tag set, and other + * application extension capabilities. + */ + +#include "tiffiop.h" + +int TIFFGetTagListCount( TIFF *tif ) + +{ + TIFFDirectory* td = &tif->tif_dir; + + return td->td_customValueCount; +} + +ttag_t TIFFGetTagListEntry( TIFF *tif, int tag_index ) + +{ + TIFFDirectory* td = &tif->tif_dir; + + if( tag_index < 0 || tag_index >= td->td_customValueCount ) + return (ttag_t) -1; + else + return td->td_customValues[tag_index].info->field_tag; +} + +/* +** This provides read/write access to the TIFFTagMethods within the TIFF +** structure to application code without giving access to the private +** TIFF structure. +*/ +TIFFTagMethods *TIFFAccessTagMethods( TIFF *tif ) + +{ + return &(tif->tif_tagmethods); +} + +void *TIFFGetClientInfo( TIFF *tif, const char *name ) + +{ + TIFFClientInfoLink *link = tif->tif_clientinfo; + + while( link != NULL && strcmp(link->name,name) != 0 ) + link = link->next; + + if( link != NULL ) + return link->data; + else + return NULL; +} + +void TIFFSetClientInfo( TIFF *tif, void *data, const char *name ) + +{ + TIFFClientInfoLink *link = tif->tif_clientinfo; + + /* + ** Do we have an existing link with this name? If so, just + ** set it. + */ + while( link != NULL && strcmp(link->name,name) != 0 ) + link = link->next; + + if( link != NULL ) + { + link->data = data; + return; + } + + /* + ** Create a new link. + */ + + link = (TIFFClientInfoLink *) _TIFFmalloc(sizeof(TIFFClientInfoLink)); + assert (link != NULL); + link->next = tif->tif_clientinfo; + link->name = (char *) _TIFFmalloc(strlen(name)+1); + assert (link->name != NULL); + strcpy(link->name, name); + link->data = data; + + tif->tif_clientinfo = link; +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_fax3.c b/thirdparty/libtiff/tif_fax3.c new file mode 100644 index 00000000..9eec4ab7 --- /dev/null +++ b/thirdparty/libtiff/tif_fax3.c @@ -0,0 +1,1626 @@ +/* $Id: tif_fax3.c,v 1.43.2.10 2010-06-09 17:16:58 bfriesen Exp $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef CCITT_SUPPORT +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support. + * + * This file contains support for decoding and encoding TIFF + * compression algorithms 2, 3, 4, and 32771. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tif_fax3.h" +#define G3CODES +#include "t4.h" +#include + +/* + * Compression+decompression state blocks are + * derived from this ``base state'' block. + */ +typedef struct { + int rw_mode; /* O_RDONLY for decode, else encode */ + int mode; /* operating mode */ + uint32 rowbytes; /* bytes in a decoded scanline */ + uint32 rowpixels; /* pixels in a scanline */ + + uint16 cleanfaxdata; /* CleanFaxData tag */ + uint32 badfaxrun; /* BadFaxRun tag */ + uint32 badfaxlines; /* BadFaxLines tag */ + uint32 groupoptions; /* Group 3/4 options tag */ + uint32 recvparams; /* encoded Class 2 session params */ + char* subaddress; /* subaddress string */ + uint32 recvtime; /* time spent receiving (secs) */ + char* faxdcs; /* Table 2/T.30 encoded session params */ + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ +} Fax3BaseState; +#define Fax3State(tif) ((Fax3BaseState*) (tif)->tif_data) + +typedef enum { G3_1D, G3_2D } Ttag; +typedef struct { + Fax3BaseState b; + + /* Decoder state info */ + const unsigned char* bitmap; /* bit reversal table */ + uint32 data; /* current i/o byte/word */ + int bit; /* current i/o bit in byte */ + int EOLcnt; /* count of EOL codes recognized */ + TIFFFaxFillFunc fill; /* fill routine */ + uint32* runs; /* b&w runs for current/previous row */ + uint32* refruns; /* runs for reference line */ + uint32* curruns; /* runs for current line */ + + /* Encoder state info */ + Ttag tag; /* encoding state */ + unsigned char* refline; /* reference line for 2d decoding */ + int k; /* #rows left that can be 2d encoded */ + int maxk; /* max #rows that can be 2d encoded */ + + int line; +} Fax3CodecState; +#define DecoderState(tif) ((Fax3CodecState*) Fax3State(tif)) +#define EncoderState(tif) ((Fax3CodecState*) Fax3State(tif)) + +#define is2DEncoding(sp) \ + (sp->b.groupoptions & GROUP3OPT_2DENCODING) +#define isAligned(p,t) ((((unsigned long)(p)) & (sizeof (t)-1)) == 0) + +/* + * Group 3 and Group 4 Decoding. + */ + +/* + * These macros glue the TIFF library state to + * the state expected by Frank's decoder. + */ +#define DECLARE_STATE(tif, sp, mod) \ + static const char module[] = mod; \ + Fax3CodecState* sp = DecoderState(tif); \ + int a0; /* reference element */ \ + int lastx = sp->b.rowpixels; /* last element in row */ \ + uint32 BitAcc; /* bit accumulator */ \ + int BitsAvail; /* # valid bits in BitAcc */ \ + int RunLength; /* length of current run */ \ + unsigned char* cp; /* next byte of input data */ \ + unsigned char* ep; /* end of input data */ \ + uint32* pa; /* place to stuff next run */ \ + uint32* thisrun; /* current row's run array */ \ + int EOLcnt; /* # EOL codes recognized */ \ + const unsigned char* bitmap = sp->bitmap; /* input data bit reverser */ \ + const TIFFFaxTabEnt* TabEnt +#define DECLARE_STATE_2D(tif, sp, mod) \ + DECLARE_STATE(tif, sp, mod); \ + int b1; /* next change on prev line */ \ + uint32* pb /* next run in reference line */\ +/* + * Load any state that may be changed during decoding. + */ +#define CACHE_STATE(tif, sp) do { \ + BitAcc = sp->data; \ + BitsAvail = sp->bit; \ + EOLcnt = sp->EOLcnt; \ + cp = (unsigned char*) tif->tif_rawcp; \ + ep = cp + tif->tif_rawcc; \ +} while (0) +/* + * Save state possibly changed during decoding. + */ +#define UNCACHE_STATE(tif, sp) do { \ + sp->bit = BitsAvail; \ + sp->data = BitAcc; \ + sp->EOLcnt = EOLcnt; \ + tif->tif_rawcc -= (tidata_t) cp - tif->tif_rawcp; \ + tif->tif_rawcp = (tidata_t) cp; \ +} while (0) + +/* + * Setup state for decoding a strip. + */ +static int +Fax3PreDecode(TIFF* tif, tsample_t s) +{ + Fax3CodecState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 0; /* force initial read */ + sp->data = 0; + sp->EOLcnt = 0; /* force initial scan for EOL */ + /* + * Decoder assumes lsb-to-msb bit order. Note that we select + * this here rather than in Fax3SetupState so that viewers can + * hold the image open, fiddle with the FillOrder tag value, + * and then re-decode the image. Otherwise they'd need to close + * and open the image to get the state reset. + */ + sp->bitmap = + TIFFGetBitRevTable(tif->tif_dir.td_fillorder != FILLORDER_LSB2MSB); + if (sp->refruns) { /* init reference line to white */ + sp->refruns[0] = (uint32) sp->b.rowpixels; + sp->refruns[1] = 0; + } + sp->line = 0; + return (1); +} + +/* + * Routine for handling various errors/conditions. + * Note how they are "glued into the decoder" by + * overriding the definitions used by the decoder. + */ + +static void +Fax3Unexpected(const char* module, TIFF* tif, uint32 line, uint32 a0) +{ + TIFFErrorExt(tif->tif_clientdata, module, "%s: Bad code word at line %u of %s %u (x %u)", + tif->tif_name, line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define unexpected(table, a0) Fax3Unexpected(module, tif, sp->line, a0) + +static void +Fax3Extension(const char* module, TIFF* tif, uint32 line, uint32 a0) +{ + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Uncompressed data (not supported) at line %u of %s %u (x %u)", + tif->tif_name, line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define extension(a0) Fax3Extension(module, tif, sp->line, a0) + +static void +Fax3BadLength(const char* module, TIFF* tif, uint32 line, uint32 a0, uint32 lastx) +{ + TIFFWarningExt(tif->tif_clientdata, module, "%s: %s at line %u of %s %u (got %u, expected %u)", + tif->tif_name, + a0 < lastx ? "Premature EOL" : "Line length mismatch", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0, lastx); +} +#define badlength(a0,lastx) Fax3BadLength(module, tif, sp->line, a0, lastx) + +static void +Fax3PrematureEOF(const char* module, TIFF* tif, uint32 line, uint32 a0) +{ + TIFFWarningExt(tif->tif_clientdata, module, "%s: Premature EOF at line %u of %s %u (x %u)", + tif->tif_name, + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0) + +#define Nop + +/* + * Decode the requested amount of G3 1D-encoded data. + */ +static int +Fax3Decode1D(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE(tif, sp, "Fax3Decode1D"); + + (void) s; + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + SYNC_EOL(EOF1D); + EXPAND1D(EOF1Da); + (*sp->fill)(buf, thisrun, pa, lastx); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOF1D: /* premature EOF */ + CLEANUP_RUNS(); + EOF1Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G3 2D-encoded data. + */ +static int +Fax3Decode2D(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE_2D(tif, sp, "Fax3Decode2D"); + int is1D; /* current line is 1d/2d-encoded */ + + (void) s; + CACHE_STATE(tif, sp); + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d EOLcnt = %d", + BitAcc, BitsAvail, EOLcnt); +#endif + SYNC_EOL(EOF2D); + NeedBits8(1, EOF2D); + is1D = GetBits(1); /* 1D/2D-encoding tag bit */ + ClrBits(1); +#ifdef FAX3_DEBUG + printf(" %s\n-------------------- %d\n", + is1D ? "1D" : "2D", tif->tif_row); + fflush(stdout); +#endif + pb = sp->refruns; + b1 = *pb++; + if (is1D) + EXPAND1D(EOF2Da); + else + EXPAND2D(EOF2Da); + (*sp->fill)(buf, thisrun, pa, lastx); + SETVALUE(0); /* imaginary change for reference */ + SWAP(uint32*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOF2D: /* premature EOF */ + CLEANUP_RUNS(); + EOF2Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * The ZERO & FILL macros must handle spans < 2*sizeof(long) bytes. + * For machines with 64-bit longs this is <16 bytes; otherwise + * this is <8 bytes. We optimize the code here to reflect the + * machine characteristics. + */ +#if SIZEOF_LONG == 8 +# define FILL(n, cp) \ + switch (n) { \ + case 15:(cp)[14] = 0xff; case 14:(cp)[13] = 0xff; case 13: (cp)[12] = 0xff;\ + case 12:(cp)[11] = 0xff; case 11:(cp)[10] = 0xff; case 10: (cp)[9] = 0xff;\ + case 9: (cp)[8] = 0xff; case 8: (cp)[7] = 0xff; case 7: (cp)[6] = 0xff;\ + case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; case 4: (cp)[3] = 0xff;\ + case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ + case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ + } +# define ZERO(n, cp) \ + switch (n) { \ + case 15:(cp)[14] = 0; case 14:(cp)[13] = 0; case 13: (cp)[12] = 0; \ + case 12:(cp)[11] = 0; case 11:(cp)[10] = 0; case 10: (cp)[9] = 0; \ + case 9: (cp)[8] = 0; case 8: (cp)[7] = 0; case 7: (cp)[6] = 0; \ + case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; case 4: (cp)[3] = 0; \ + case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ + case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ + } +#else +# define FILL(n, cp) \ + switch (n) { \ + case 7: (cp)[6] = 0xff; case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; \ + case 4: (cp)[3] = 0xff; case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ + case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ + } +# define ZERO(n, cp) \ + switch (n) { \ + case 7: (cp)[6] = 0; case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; \ + case 4: (cp)[3] = 0; case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ + case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ + } +#endif + +/* + * Bit-fill a row according to the white/black + * runs generated during G3/G4 decoding. + */ +void +_TIFFFax3fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) +{ + static const unsigned char _fillmasks[] = + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + unsigned char* cp; + uint32 x, bx, run; + int32 n, nw; + long* lp; + + if ((erun-runs)&1) + *erun++ = 0; + x = 0; + for (; runs < erun; runs += 2) { + run = runs[0]; + if (x+run > lastx || run > lastx ) + run = runs[0] = (uint32) (lastx - x); + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ &= 0xff << (8-bx); + run -= 8-bx; + } + if( (n = run >> 3) != 0 ) { /* multiple bytes to fill */ + if ((n/sizeof (long)) > 1) { + /* + * Align to longword boundary and fill. + */ + for (; n && !isAligned(cp, long); n--) + *cp++ = 0x00; + lp = (long*) cp; + nw = (int32)(n / sizeof (long)); + n -= nw * sizeof (long); + do { + *lp++ = 0L; + } while (--nw); + cp = (unsigned char*) lp; + } + ZERO(n, cp); + run &= 7; + } + if (run) + cp[0] &= 0xff >> run; + } else + cp[0] &= ~(_fillmasks[run]>>bx); + x += runs[0]; + } + run = runs[1]; + if (x+run > lastx || run > lastx ) + run = runs[1] = lastx - x; + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ |= 0xff >> bx; + run -= 8-bx; + } + if( (n = run>>3) != 0 ) { /* multiple bytes to fill */ + if ((n/sizeof (long)) > 1) { + /* + * Align to longword boundary and fill. + */ + for (; n && !isAligned(cp, long); n--) + *cp++ = 0xff; + lp = (long*) cp; + nw = (int32)(n / sizeof (long)); + n -= nw * sizeof (long); + do { + *lp++ = -1L; + } while (--nw); + cp = (unsigned char*) lp; + } + FILL(n, cp); + run &= 7; + } + if (run) + cp[0] |= 0xff00 >> run; + } else + cp[0] |= _fillmasks[run]>>bx; + x += runs[1]; + } + } + assert(x == lastx); +} +#undef ZERO +#undef FILL + +/* + * Setup G3/G4-related compression/decompression state + * before data is processed. This routine is called once + * per image -- it sets up different state based on whether + * or not decoding or encoding is being done and whether + * 1D- or 2D-encoded data is involved. + */ +static int +Fax3SetupState(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + Fax3BaseState* sp = Fax3State(tif); + int needsRefLine; + Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif); + uint32 rowbytes, rowpixels, nruns; + + if (td->td_bitspersample != 1) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Bits/sample must be 1 for Group 3/4 encoding/decoding"); + return (0); + } + /* + * Calculate the scanline/tile widths. + */ + if (isTiled(tif)) { + rowbytes = TIFFTileRowSize(tif); + rowpixels = td->td_tilewidth; + } else { + rowbytes = TIFFScanlineSize(tif); + rowpixels = td->td_imagewidth; + } + sp->rowbytes = (uint32) rowbytes; + sp->rowpixels = (uint32) rowpixels; + /* + * Allocate any additional space required for decoding/encoding. + */ + needsRefLine = ( + (sp->groupoptions & GROUP3OPT_2DENCODING) || + td->td_compression == COMPRESSION_CCITTFAX4 + ); + + /* + Assure that allocation computations do not overflow. + + TIFFroundup and TIFFSafeMultiply return zero on integer overflow + */ + dsp->runs=(uint32*) NULL; + nruns = TIFFroundup(rowpixels,32); + if (needsRefLine) { + nruns = TIFFSafeMultiply(uint32,nruns,2); + } + if ((nruns == 0) || (TIFFSafeMultiply(uint32,nruns,2) == 0)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Row pixels integer overflow (rowpixels %u)", + rowpixels); + return (0); + } + dsp->runs = (uint32*) _TIFFCheckMalloc(tif, + TIFFSafeMultiply(uint32,nruns,2), + sizeof (uint32), + "for Group 3/4 run arrays"); + if (dsp->runs == NULL) + return (0); + dsp->curruns = dsp->runs; + if (needsRefLine) + dsp->refruns = dsp->runs + nruns; + else + dsp->refruns = NULL; + if (td->td_compression == COMPRESSION_CCITTFAX3 + && is2DEncoding(dsp)) { /* NB: default is 1D routine */ + tif->tif_decoderow = Fax3Decode2D; + tif->tif_decodestrip = Fax3Decode2D; + tif->tif_decodetile = Fax3Decode2D; + } + + if (needsRefLine) { /* 2d encoding */ + Fax3CodecState* esp = EncoderState(tif); + /* + * 2d encoding requires a scanline + * buffer for the ``reference line''; the + * scanline against which delta encoding + * is referenced. The reference line must + * be initialized to be ``white'' (done elsewhere). + */ + esp->refline = (unsigned char*) _TIFFmalloc(rowbytes); + if (esp->refline == NULL) { + TIFFErrorExt(tif->tif_clientdata, "Fax3SetupState", + "%s: No space for Group 3/4 reference line", + tif->tif_name); + return (0); + } + } else /* 1d encoding */ + EncoderState(tif)->refline = NULL; + + return (1); +} + +/* + * CCITT Group 3 FAX Encoding. + */ + +#define Fax3FlushBits(tif, sp) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ + (void) TIFFFlushData1(tif); \ + *(tif)->tif_rawcp++ = (tidataval_t) (sp)->data; \ + (tif)->tif_rawcc++; \ + (sp)->data = 0, (sp)->bit = 8; \ +} +#define _FlushBits(tif) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ + (void) TIFFFlushData1(tif); \ + *(tif)->tif_rawcp++ = (tidataval_t) data; \ + (tif)->tif_rawcc++; \ + data = 0, bit = 8; \ +} +static const int _msbmask[9] = + { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; +#define _PutBits(tif, bits, length) { \ + while (length > bit) { \ + data |= bits >> (length - bit); \ + length -= bit; \ + _FlushBits(tif); \ + } \ + data |= (bits & _msbmask[length]) << (bit - length); \ + bit -= length; \ + if (bit == 0) \ + _FlushBits(tif); \ +} + +/* + * Write a variable-length bit-value to + * the output stream. Values are + * assumed to be at most 16 bits. + */ +static void +Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length) +{ + Fax3CodecState* sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; + + _PutBits(tif, bits, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Write a code to the output stream. + */ +#define putcode(tif, te) Fax3PutBits(tif, (te)->code, (te)->length) + +#ifdef FAX3_DEBUG +#define DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B") +#define DEBUG_PRINT(what,len) { \ + int t; \ + printf("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len); \ + for (t = length-1; t >= 0; t--) \ + putchar(code & (1<bit; + int data = sp->data; + unsigned int code, length; + + while (span >= 2624) { + const tableentry* te = &tab[63 + (2560>>6)]; + code = te->code, length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + if (span >= 64) { + const tableentry* te = &tab[63 + (span>>6)]; + assert(te->runlen == 64*(span>>6)); + code = te->code, length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + code = tab[span].code, length = tab[span].length; +#ifdef FAX3_DEBUG + DEBUG_PRINT(" Term", tab[span].runlen); +#endif + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Write an EOL code to the output stream. The zero-fill + * logic for byte-aligning encoded scanlines is handled + * here. We also handle writing the tag bit for the next + * scanline when doing 2d encoding. + */ +static void +Fax3PutEOL(TIFF* tif) +{ + Fax3CodecState* sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; + unsigned int code, length, tparm; + + if (sp->b.groupoptions & GROUP3OPT_FILLBITS) { + /* + * Force bit alignment so EOL will terminate on + * a byte boundary. That is, force the bit alignment + * to 16-12 = 4 before putting out the EOL code. + */ + int align = 8 - 4; + if (align != sp->bit) { + if (align > sp->bit) + align = sp->bit + (8 - align); + else + align = sp->bit - align; + code = 0; + tparm=align; + _PutBits(tif, 0, tparm); + } + } + code = EOL, length = 12; + if (is2DEncoding(sp)) + code = (code<<1) | (sp->tag == G3_1D), length++; + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +Fax3PreEncode(TIFF* tif, tsample_t s) +{ + Fax3CodecState* sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 8; + sp->data = 0; + sp->tag = G3_1D; + /* + * This is necessary for Group 4; otherwise it isn't + * needed because the first scanline of each strip ends + * up being copied into the refline. + */ + if (sp->refline) + _TIFFmemset(sp->refline, 0x00, sp->b.rowbytes); + if (is2DEncoding(sp)) { + float res = tif->tif_dir.td_yresolution; + /* + * The CCITT spec says that when doing 2d encoding, you + * should only do it on K consecutive scanlines, where K + * depends on the resolution of the image being encoded + * (2 for <= 200 lpi, 4 for > 200 lpi). Since the directory + * code initializes td_yresolution to 0, this code will + * select a K of 2 unless the YResolution tag is set + * appropriately. (Note also that we fudge a little here + * and use 150 lpi to avoid problems with units conversion.) + */ + if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER) + res *= 2.54f; /* convert to inches */ + sp->maxk = (res > 150 ? 4 : 2); + sp->k = sp->maxk-1; + } else + sp->k = sp->maxk = 0; + sp->line = 0; + return (1); +} + +static const unsigned char zeroruns[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */ +}; +static const unsigned char oneruns[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */ +}; + +/* + * On certain systems it pays to inline + * the routines that find pixel spans. + */ +#ifdef VAXC +static int32 find0span(unsigned char*, int32, int32); +static int32 find1span(unsigned char*, int32, int32); +#pragma inline(find0span,find1span) +#endif + +/* + * Find a span of ones or zeros using the supplied + * table. The ``base'' of the bit string is supplied + * along with the start+end bit indices. + */ +static int32 +find0span(unsigned char* bp, int32 bs, int32 be) +{ + int32 bits = be - bs; + int32 n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7))) { + span = zeroruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= (int32)(2 * 8 * sizeof(long))) { + long* lp; + /* + * Align to longword boundary and check longwords. + */ + while (!isAligned(bp, long)) { + if (*bp != 0x00) + return (span + zeroruns[*bp]); + span += 8, bits -= 8; + bp++; + } + lp = (long*) bp; + while ((bits >= (int32)(8 * sizeof(long))) && (0 == *lp)) { + span += 8*sizeof (long), bits -= 8*sizeof (long); + lp++; + } + bp = (unsigned char*) lp; + } + /* + * Scan full bytes for all 0's. + */ + while (bits >= 8) { + if (*bp != 0x00) /* end of run */ + return (span + zeroruns[*bp]); + span += 8, bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = zeroruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +static int32 +find1span(unsigned char* bp, int32 bs, int32 be) +{ + int32 bits = be - bs; + int32 n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7))) { + span = oneruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= (int32)(2 * 8 * sizeof(long))) { + long* lp; + /* + * Align to longword boundary and check longwords. + */ + while (!isAligned(bp, long)) { + if (*bp != 0xff) + return (span + oneruns[*bp]); + span += 8, bits -= 8; + bp++; + } + lp = (long*) bp; + while ((bits >= (int32)(8 * sizeof(long))) && (~0 == *lp)) { + span += 8*sizeof (long), bits -= 8*sizeof (long); + lp++; + } + bp = (unsigned char*) lp; + } + /* + * Scan full bytes for all 1's. + */ + while (bits >= 8) { + if (*bp != 0xff) /* end of run */ + return (span + oneruns[*bp]); + span += 8, bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = oneruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +/* + * Return the offset of the next bit in the range + * [bs..be] that is different from the specified + * color. The end, be, is returned if no such bit + * exists. + */ +#define finddiff(_cp, _bs, _be, _color) \ + (_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be))) +/* + * Like finddiff, but also check the starting bit + * against the end in case start > end. + */ +#define finddiff2(_cp, _bs, _be, _color) \ + (_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be) + +/* + * 1d-encode a row of pixels. The encoding is + * a sequence of all-white or all-black spans + * of pixels encoded with Huffman codes. + */ +static int +Fax3Encode1DRow(TIFF* tif, unsigned char* bp, uint32 bits) +{ + Fax3CodecState* sp = EncoderState(tif); + int32 span; + uint32 bs = 0; + + for (;;) { + span = find0span(bp, bs, bits); /* white span */ + putspan(tif, span, TIFFFaxWhiteCodes); + bs += span; + if (bs >= bits) + break; + span = find1span(bp, bs, bits); /* black span */ + putspan(tif, span, TIFFFaxBlackCodes); + bs += span; + if (bs >= bits) + break; + } + if (sp->b.mode & (FAXMODE_BYTEALIGN|FAXMODE_WORDALIGN)) { + if (sp->bit != 8) /* byte-align */ + Fax3FlushBits(tif, sp); + if ((sp->b.mode&FAXMODE_WORDALIGN) && + !isAligned(tif->tif_rawcp, uint16)) + Fax3FlushBits(tif, sp); + } + return (1); +} + +static const tableentry horizcode = + { 3, 0x1, 0 }; /* 001 */ +static const tableentry passcode = + { 4, 0x1, 0 }; /* 0001 */ +static const tableentry vcodes[7] = { + { 7, 0x03, 0 }, /* 0000 011 */ + { 6, 0x03, 0 }, /* 0000 11 */ + { 3, 0x03, 0 }, /* 011 */ + { 1, 0x1, 0 }, /* 1 */ + { 3, 0x2, 0 }, /* 010 */ + { 6, 0x02, 0 }, /* 0000 10 */ + { 7, 0x02, 0 } /* 0000 010 */ +}; + +/* + * 2d-encode a row of pixels. Consult the CCITT + * documentation for the algorithm. + */ +static int +Fax3Encode2DRow(TIFF* tif, unsigned char* bp, unsigned char* rp, uint32 bits) +{ +#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1) + uint32 a0 = 0; + uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0)); + uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0)); + uint32 a2, b2; + + for (;;) { + b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1)); + if (b2 >= a1) { + int32 d = b1 - a1; + if (!(-3 <= d && d <= 3)) { /* horizontal mode */ + a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1)); + putcode(tif, &horizcode); + if (a0+a1 == 0 || PIXEL(bp, a0) == 0) { + putspan(tif, a1-a0, TIFFFaxWhiteCodes); + putspan(tif, a2-a1, TIFFFaxBlackCodes); + } else { + putspan(tif, a1-a0, TIFFFaxBlackCodes); + putspan(tif, a2-a1, TIFFFaxWhiteCodes); + } + a0 = a2; + } else { /* vertical mode */ + putcode(tif, &vcodes[d+3]); + a0 = a1; + } + } else { /* pass mode */ + putcode(tif, &passcode); + a0 = b2; + } + if (a0 >= bits) + break; + a1 = finddiff(bp, a0, bits, PIXEL(bp,a0)); + b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0)); + b1 = finddiff(rp, b1, bits, PIXEL(bp,a0)); + } + return (1); +#undef PIXEL +} + +/* + * Encode a buffer of pixels. + */ +static int +Fax3Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + Fax3CodecState* sp = EncoderState(tif); + + (void) s; + while ((long)cc > 0) { + if ((sp->b.mode & FAXMODE_NOEOL) == 0) + Fax3PutEOL(tif); + if (is2DEncoding(sp)) { + if (sp->tag == G3_1D) { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + sp->tag = G3_2D; + } else { + if (!Fax3Encode2DRow(tif, bp, sp->refline, + sp->b.rowpixels)) + return (0); + sp->k--; + } + if (sp->k == 0) { + sp->tag = G3_1D; + sp->k = sp->maxk-1; + } else + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + } else { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + } + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + } + return (1); +} + +static int +Fax3PostEncode(TIFF* tif) +{ + Fax3CodecState* sp = EncoderState(tif); + + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +static void +Fax3Close(TIFF* tif) +{ + if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0) { + Fax3CodecState* sp = EncoderState(tif); + unsigned int code = EOL; + unsigned int length = 12; + int i; + + if (is2DEncoding(sp)) + code = (code<<1) | (sp->tag == G3_1D), length++; + for (i = 0; i < 6; i++) + Fax3PutBits(tif, code, length); + Fax3FlushBits(tif, sp); + } +} + +static void +Fax3Cleanup(TIFF* tif) +{ + Fax3CodecState* sp = DecoderState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->b.vgetparent; + tif->tif_tagmethods.vsetfield = sp->b.vsetparent; + tif->tif_tagmethods.printdir = sp->b.printdir; + + if (sp->runs) + _TIFFfree(sp->runs); + if (sp->refline) + _TIFFfree(sp->refline); + + if (Fax3State(tif)->subaddress) + _TIFFfree(Fax3State(tif)->subaddress); + if (Fax3State(tif)->faxdcs) + _TIFFfree(Fax3State(tif)->faxdcs); + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +#define FIELD_BADFAXLINES (FIELD_CODEC+0) +#define FIELD_CLEANFAXDATA (FIELD_CODEC+1) +#define FIELD_BADFAXRUN (FIELD_CODEC+2) +#define FIELD_RECVPARAMS (FIELD_CODEC+3) +#define FIELD_SUBADDRESS (FIELD_CODEC+4) +#define FIELD_RECVTIME (FIELD_CODEC+5) +#define FIELD_FAXDCS (FIELD_CODEC+6) + +#define FIELD_OPTIONS (FIELD_CODEC+7) + +static const TIFFFieldInfo faxFieldInfo[] = { + { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "FaxMode" }, + { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "FaxFillFunc" }, + { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, FIELD_BADFAXLINES, + TRUE, FALSE, "BadFaxLines" }, + { TIFFTAG_BADFAXLINES, 1, 1, TIFF_SHORT, FIELD_BADFAXLINES, + TRUE, FALSE, "BadFaxLines" }, + { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, FIELD_CLEANFAXDATA, + TRUE, FALSE, "CleanFaxData" }, + { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_LONG, FIELD_BADFAXRUN, + TRUE, FALSE, "ConsecutiveBadFaxLines" }, + { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_SHORT, FIELD_BADFAXRUN, + TRUE, FALSE, "ConsecutiveBadFaxLines" }, + { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, + TRUE, FALSE, "FaxRecvParams" }, + { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS, + TRUE, FALSE, "FaxSubAddress" }, + { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, + TRUE, FALSE, "FaxRecvTime" }, + { TIFFTAG_FAXDCS, -1,-1, TIFF_ASCII, FIELD_FAXDCS, + TRUE, FALSE, "FaxDcs" }, +}; +static const TIFFFieldInfo fax3FieldInfo[] = { + { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS, + FALSE, FALSE, "Group3Options" }, +}; +static const TIFFFieldInfo fax4FieldInfo[] = { + { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS, + FALSE, FALSE, "Group4Options" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +static int +Fax3VSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + const TIFFFieldInfo* fip; + + assert(sp != 0); + assert(sp->vsetparent != 0); + + switch (tag) { + case TIFFTAG_FAXMODE: + sp->mode = va_arg(ap, int); + return 1; /* NB: pseudo tag */ + case TIFFTAG_FAXFILLFUNC: + DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc); + return 1; /* NB: pseudo tag */ + case TIFFTAG_GROUP3OPTIONS: + /* XXX: avoid reading options if compression mismatches. */ + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3) + sp->groupoptions = va_arg(ap, uint32); + break; + case TIFFTAG_GROUP4OPTIONS: + /* XXX: avoid reading options if compression mismatches. */ + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) + sp->groupoptions = va_arg(ap, uint32); + break; + case TIFFTAG_BADFAXLINES: + sp->badfaxlines = va_arg(ap, uint32); + break; + case TIFFTAG_CLEANFAXDATA: + sp->cleanfaxdata = (uint16) va_arg(ap, int); + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + sp->badfaxrun = va_arg(ap, uint32); + break; + case TIFFTAG_FAXRECVPARAMS: + sp->recvparams = va_arg(ap, uint32); + break; + case TIFFTAG_FAXSUBADDRESS: + _TIFFsetString(&sp->subaddress, va_arg(ap, char*)); + break; + case TIFFTAG_FAXRECVTIME: + sp->recvtime = va_arg(ap, uint32); + break; + case TIFFTAG_FAXDCS: + _TIFFsetString(&sp->faxdcs, va_arg(ap, char*)); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + + if ((fip = _TIFFFieldWithTag(tif, tag))) + TIFFSetFieldBit(tif, fip->field_bit); + else + return 0; + + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +static int +Fax3VGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + + assert(sp != 0); + + switch (tag) { + case TIFFTAG_FAXMODE: + *va_arg(ap, int*) = sp->mode; + break; + case TIFFTAG_FAXFILLFUNC: + *va_arg(ap, TIFFFaxFillFunc*) = DecoderState(tif)->fill; + break; + case TIFFTAG_GROUP3OPTIONS: + case TIFFTAG_GROUP4OPTIONS: + *va_arg(ap, uint32*) = sp->groupoptions; + break; + case TIFFTAG_BADFAXLINES: + *va_arg(ap, uint32*) = sp->badfaxlines; + break; + case TIFFTAG_CLEANFAXDATA: + *va_arg(ap, uint16*) = sp->cleanfaxdata; + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + *va_arg(ap, uint32*) = sp->badfaxrun; + break; + case TIFFTAG_FAXRECVPARAMS: + *va_arg(ap, uint32*) = sp->recvparams; + break; + case TIFFTAG_FAXSUBADDRESS: + *va_arg(ap, char**) = sp->subaddress; + break; + case TIFFTAG_FAXRECVTIME: + *va_arg(ap, uint32*) = sp->recvtime; + break; + case TIFFTAG_FAXDCS: + *va_arg(ap, char**) = sp->faxdcs; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +Fax3PrintDir(TIFF* tif, FILE* fd, long flags) +{ + Fax3BaseState* sp = Fax3State(tif); + + assert(sp != 0); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_OPTIONS)) { + const char* sep = " "; + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) { + fprintf(fd, " Group 4 Options:"); + if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } else { + + fprintf(fd, " Group 3 Options:"); + if (sp->groupoptions & GROUP3OPT_2DENCODING) + fprintf(fd, "%s2-d encoding", sep), sep = "+"; + if (sp->groupoptions & GROUP3OPT_FILLBITS) + fprintf(fd, "%sEOL padding", sep), sep = "+"; + if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } + fprintf(fd, " (%lu = 0x%lx)\n", + (unsigned long) sp->groupoptions, + (unsigned long) sp->groupoptions); + } + if (TIFFFieldSet(tif,FIELD_CLEANFAXDATA)) { + fprintf(fd, " Fax Data:"); + switch (sp->cleanfaxdata) { + case CLEANFAXDATA_CLEAN: + fprintf(fd, " clean"); + break; + case CLEANFAXDATA_REGENERATED: + fprintf(fd, " receiver regenerated"); + break; + case CLEANFAXDATA_UNCLEAN: + fprintf(fd, " uncorrected errors"); + break; + } + fprintf(fd, " (%u = 0x%x)\n", + sp->cleanfaxdata, sp->cleanfaxdata); + } + if (TIFFFieldSet(tif,FIELD_BADFAXLINES)) + fprintf(fd, " Bad Fax Lines: %lu\n", + (unsigned long) sp->badfaxlines); + if (TIFFFieldSet(tif,FIELD_BADFAXRUN)) + fprintf(fd, " Consecutive Bad Fax Lines: %lu\n", + (unsigned long) sp->badfaxrun); + if (TIFFFieldSet(tif,FIELD_RECVPARAMS)) + fprintf(fd, " Fax Receive Parameters: %08lx\n", + (unsigned long) sp->recvparams); + if (TIFFFieldSet(tif,FIELD_SUBADDRESS)) + fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress); + if (TIFFFieldSet(tif,FIELD_RECVTIME)) + fprintf(fd, " Fax Receive Time: %lu secs\n", + (unsigned long) sp->recvtime); + if (TIFFFieldSet(tif,FIELD_FAXDCS)) + fprintf(fd, " Fax DCS: %s\n", sp->faxdcs); +} + +static int +InitCCITTFax3(TIFF* tif) +{ + Fax3BaseState* sp; + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, faxFieldInfo, N(faxFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, "InitCCITTFax3", + "Merging common CCITT Fax codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) + _TIFFmalloc(sizeof (Fax3CodecState)); + + if (tif->tif_data == NULL) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3", + "%s: No space for state block", tif->tif_name); + return (0); + } + + sp = Fax3State(tif); + sp->rw_mode = tif->tif_mode; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = Fax3VGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = Fax3VSetField; /* hook for codec tags */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = Fax3PrintDir; /* hook for codec tags */ + sp->groupoptions = 0; + sp->recvparams = 0; + sp->subaddress = NULL; + sp->faxdcs = NULL; + + if (sp->rw_mode == O_RDONLY) /* FIXME: improve for in place update */ + tif->tif_flags |= TIFF_NOBITREV; /* decoder does bit reversal */ + DecoderState(tif)->runs = NULL; + TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns); + EncoderState(tif)->refline = NULL; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = Fax3SetupState; + tif->tif_predecode = Fax3PreDecode; + tif->tif_decoderow = Fax3Decode1D; + tif->tif_decodestrip = Fax3Decode1D; + tif->tif_decodetile = Fax3Decode1D; + tif->tif_setupencode = Fax3SetupState; + tif->tif_preencode = Fax3PreEncode; + tif->tif_postencode = Fax3PostEncode; + tif->tif_encoderow = Fax3Encode; + tif->tif_encodestrip = Fax3Encode; + tif->tif_encodetile = Fax3Encode; + tif->tif_close = Fax3Close; + tif->tif_cleanup = Fax3Cleanup; + + return (1); +} + +int +TIFFInitCCITTFax3(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, fax3FieldInfo, N(fax3FieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3", + "Merging CCITT Fax 3 codec-specific tags failed"); + return 0; + } + + /* + * The default format is Class/F-style w/o RTC. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + } else + return 01; +} + +/* + * CCITT Group 4 (T.6) Facsimile-compatible + * Compression Scheme Support. + */ + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G4-encoded data. + */ +static int +Fax4Decode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE_2D(tif, sp, "Fax4Decode"); + + (void) s; + CACHE_STATE(tif, sp); + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; + pb = sp->refruns; + b1 = *pb++; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND2D(EOFG4); + if (EOLcnt) + goto EOFG4; + (*sp->fill)(buf, thisrun, pa, lastx); + SETVALUE(0); /* imaginary change for reference */ + SWAP(uint32*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOFG4: + NeedBits16( 13, BADG4 ); + BADG4: +#ifdef FAX3_DEBUG + if( GetBits(13) != 0x1001 ) + fputs( "Bad EOFB\n", stderr ); +#endif + ClrBits( 13 ); + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return ( sp->line ? 1 : -1); /* don't error on badly-terminated strips */ + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * Encode the requested amount of data. + */ +static int +Fax4Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + Fax3CodecState *sp = EncoderState(tif); + + (void) s; + while ((long)cc > 0) { + if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels)) + return (0); + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + } + return (1); +} + +static int +Fax4PostEncode(TIFF* tif) +{ + Fax3CodecState *sp = EncoderState(tif); + + /* terminate strip w/ EOFB */ + Fax3PutBits(tif, EOL, 12); + Fax3PutBits(tif, EOL, 12); + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +int +TIFFInitCCITTFax4(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, fax4FieldInfo, N(fax4FieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax4", + "Merging CCITT Fax 4 codec-specific tags failed"); + return 0; + } + + tif->tif_decoderow = Fax4Decode; + tif->tif_decodestrip = Fax4Decode; + tif->tif_decodetile = Fax4Decode; + tif->tif_encoderow = Fax4Encode; + tif->tif_encodestrip = Fax4Encode; + tif->tif_encodetile = Fax4Encode; + tif->tif_postencode = Fax4PostEncode; + /* + * Suppress RTC at the end of each strip. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC); + } else + return (0); +} + +/* + * CCITT Group 3 1-D Modified Huffman RLE Compression Support. + * (Compression algorithms 2 and 32771) + */ + +/* + * Decode the requested amount of RLE-encoded data. + */ +static int +Fax3DecodeRLE(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE(tif, sp, "Fax3DecodeRLE"); + int mode = sp->b.mode; + + (void) s; + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND1D(EOFRLE); + (*sp->fill)(buf, thisrun, pa, lastx); + /* + * Cleanup at the end of the row. + */ + if (mode & FAXMODE_BYTEALIGN) { + int n = BitsAvail - (BitsAvail &~ 7); + ClrBits(n); + } else if (mode & FAXMODE_WORDALIGN) { + int n = BitsAvail - (BitsAvail &~ 15); + ClrBits(n); + if (BitsAvail == 0 && !isAligned(cp, uint16)) + cp++; + } + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOFRLE: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +int +TIFFInitCCITTRLE(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and byte-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN); + } else + return (0); +} + +int +TIFFInitCCITTRLEW(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and word-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN); + } else + return (0); +} +#endif /* CCITT_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_fax3.h b/thirdparty/libtiff/tif_fax3.h new file mode 100644 index 00000000..40718bcf --- /dev/null +++ b/thirdparty/libtiff/tif_fax3.h @@ -0,0 +1,532 @@ +/* $Id: tif_fax3.h,v 1.5.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _FAX3_ +#define _FAX3_ +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tiff.h" + +/* + * To override the default routine used to image decoded + * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC. + * The routine must have the type signature given below; + * for example: + * + * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) + * + * where buf is place to set the bits, runs is the array of b&w run + * lengths (white then black), erun is the last run in the array, and + * lastx is the width of the row in pixels. Fill routines can assume + * the run array has room for at least lastx runs and can overwrite + * data in the run array as needed (e.g. to append zero runs to bring + * the count up to a nice multiple). + */ +typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32); + +/* + * The default run filler; made external for other decoders. + */ +#if defined(__cplusplus) +extern "C" { +#endif +extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32); +#if defined(__cplusplus) +} +#endif + + +/* finite state machine codes */ +#define S_Null 0 +#define S_Pass 1 +#define S_Horiz 2 +#define S_V0 3 +#define S_VR 4 +#define S_VL 5 +#define S_Ext 6 +#define S_TermW 7 +#define S_TermB 8 +#define S_MakeUpW 9 +#define S_MakeUpB 10 +#define S_MakeUp 11 +#define S_EOL 12 + +typedef struct { /* state table entry */ + unsigned char State; /* see above */ + unsigned char Width; /* width of code in bits */ + uint32 Param; /* unsigned 32-bit run length in bits */ +} TIFFFaxTabEnt; + +extern const TIFFFaxTabEnt TIFFFaxMainTable[]; +extern const TIFFFaxTabEnt TIFFFaxWhiteTable[]; +extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; + +/* + * The following macros define the majority of the G3/G4 decoder + * algorithm using the state tables defined elsewhere. To build + * a decoder you need some setup code and some glue code. Note + * that you may also need/want to change the way the NeedBits* + * macros get input data if, for example, you know the data to be + * decoded is properly aligned and oriented (doing so before running + * the decoder can be a big performance win). + * + * Consult the decoder in the TIFF library for an idea of what you + * need to define and setup to make use of these definitions. + * + * NB: to enable a debugging version of these macros define FAX3_DEBUG + * before including this file. Trace output goes to stdout. + */ + +#ifndef EndOfData +#define EndOfData() (cp >= ep) +#endif +/* + * Need <=8 or <=16 bits of input data. Unlike viewfax we + * cannot use/assume a word-aligned, properly bit swizzled + * input data set because data may come from an arbitrarily + * aligned, read-only source such as a memory-mapped file. + * Note also that the viewfax decoder does not check for + * running off the end of the input data buffer. This is + * possible for G3-encoded data because it prescans the input + * data to count EOL markers, but can cause problems for G4 + * data. In any event, we don't prescan and must watch for + * running out of data since we can't permit the library to + * scan past the end of the input data buffer. + * + * Finally, note that we must handle remaindered data at the end + * of a strip specially. The coder asks for a fixed number of + * bits when scanning for the next code. This may be more bits + * than are actually present in the data stream. If we appear + * to run out of data but still have some number of valid bits + * remaining then we makeup the requested amount with zeros and + * return successfully. If the returned data is incorrect then + * we should be called again and get a premature EOF error; + * otherwise we should get the right answer. + */ +#ifndef NeedBits8 +#define NeedBits8(n,eoflab) do { \ + if (BitsAvail < (n)) { \ + if (EndOfData()) { \ + if (BitsAvail == 0) /* no valid bits */ \ + goto eoflab; \ + BitsAvail = (n); /* pad with zeros */ \ + } else { \ + BitAcc |= ((uint32) bitmap[*cp++])<>= (n); \ +} while (0) + +#ifdef FAX3_DEBUG +static const char* StateNames[] = { + "Null ", + "Pass ", + "Horiz ", + "V0 ", + "VR ", + "VL ", + "Ext ", + "TermW ", + "TermB ", + "MakeUpW", + "MakeUpB", + "MakeUp ", + "EOL ", +}; +#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') +#define LOOKUP8(wid,tab,eoflab) do { \ + int t; \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + int t; \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVALUE(x) do { \ + *pa++ = RunLength + (x); \ + printf("SETVALUE: %d\t%d\n", RunLength + (x), a0); \ + a0 += x; \ + RunLength = 0; \ +} while (0) +#else +#define LOOKUP8(wid,tab,eoflab) do { \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) + +/* + * Append a run to the run length array for the + * current row and reset decoding state. + */ +#define SETVALUE(x) do { \ + *pa++ = RunLength + (x); \ + a0 += (x); \ + RunLength = 0; \ +} while (0) +#endif + +/* + * Synchronize input decoding at the start of each + * row by scanning for an EOL (if appropriate) and + * skipping any trash data that might be present + * after a decoding error. Note that the decoding + * done elsewhere that recognizes an EOL only consumes + * 11 consecutive zero bits. This means that if EOLcnt + * is non-zero then we still need to scan for the final flag + * bit that is part of the EOL code. + */ +#define SYNC_EOL(eoflab) do { \ + if (EOLcnt == 0) { \ + for (;;) { \ + NeedBits16(11,eoflab); \ + if (GetBits(11) == 0) \ + break; \ + ClrBits(1); \ + } \ + } \ + for (;;) { \ + NeedBits8(8,eoflab); \ + if (GetBits(8)) \ + break; \ + ClrBits(8); \ + } \ + while (GetBits(1) == 0) \ + ClrBits(1); \ + ClrBits(1); /* EOL bit */ \ + EOLcnt = 0; /* reset EOL counter/flag */ \ +} while (0) + +/* + * Cleanup the array of runs after decoding a row. + * We adjust final runs to insure the user buffer is not + * overwritten and/or undecoded area is white filled. + */ +#define CLEANUP_RUNS() do { \ + if (RunLength) \ + SETVALUE(0); \ + if (a0 != lastx) { \ + badlength(a0, lastx); \ + while (a0 > lastx && pa > thisrun) \ + a0 -= *--pa; \ + if (a0 < lastx) { \ + if (a0 < 0) \ + a0 = 0; \ + if ((pa-thisrun)&1) \ + SETVALUE(0); \ + SETVALUE(lastx - a0); \ + } else if (a0 > lastx) { \ + SETVALUE(lastx); \ + SETVALUE(0); \ + } \ + } \ +} while (0) + +/* + * Decode a line of 1D-encoded data. + * + * The line expanders are written as macros so that they can be reused + * but still have direct access to the local variables of the "calling" + * function. + * + * Note that unlike the original version we have to explicitly test for + * a0 >= lastx after each black/white run is decoded. This is because + * the original code depended on the input data being zero-padded to + * insure the decoder recognized an EOL before running out of data. + */ +#define EXPAND1D(eoflab) do { \ + for (;;) { \ + for (;;) { \ + LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite1d; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", a0); \ + goto done1d; \ + } \ + } \ + doneWhite1d: \ + if (a0 >= lastx) \ + goto done1d; \ + for (;;) { \ + LOOKUP16(13, TIFFFaxBlackTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack1d; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", a0); \ + goto done1d; \ + } \ + } \ + doneBlack1d: \ + if (a0 >= lastx) \ + goto done1d; \ + if( *(pa-1) == 0 && *(pa-2) == 0 ) \ + pa -= 2; \ + } \ +eof1d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ +done1d: \ + CLEANUP_RUNS(); \ +} while (0) + +/* + * Update the value of b1 using the array + * of runs for the reference line. + */ +#define CHECK_b1 do { \ + if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ + b1 += pb[0] + pb[1]; \ + pb += 2; \ + } \ +} while (0) + +/* + * Expand a row of 2D-encoded data. + */ +#define EXPAND2D(eoflab) do { \ + while (a0 < lastx) { \ + LOOKUP8(7, TIFFFaxMainTable, eof2d); \ + switch (TabEnt->State) { \ + case S_Pass: \ + CHECK_b1; \ + b1 += *pb++; \ + RunLength += b1 - a0; \ + a0 = b1; \ + b1 += *pb++; \ + break; \ + case S_Horiz: \ + if ((pa-thisrun)&1) { \ + for (;;) { /* black first */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite2da; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneWhite2da:; \ + for (;;) { /* then white */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack2da; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneBlack2da:; \ + } else { \ + for (;;) { /* white first */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite2db; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneWhite2db:; \ + for (;;) { /* then black */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack2db; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneBlack2db:; \ + } \ + CHECK_b1; \ + break; \ + case S_V0: \ + CHECK_b1; \ + SETVALUE(b1 - a0); \ + b1 += *pb++; \ + break; \ + case S_VR: \ + CHECK_b1; \ + SETVALUE(b1 - a0 + TabEnt->Param); \ + b1 += *pb++; \ + break; \ + case S_VL: \ + CHECK_b1; \ + SETVALUE(b1 - a0 - TabEnt->Param); \ + b1 -= *--pb; \ + break; \ + case S_Ext: \ + *pa++ = lastx - a0; \ + extension(a0); \ + goto eol2d; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits8(4,eof2d); \ + if (GetBits(4)) \ + unexpected("EOL", a0); \ + ClrBits(4); \ + EOLcnt = 1; \ + goto eol2d; \ + default: \ + badMain2d: \ + unexpected("MainTable", a0); \ + goto eol2d; \ + badBlack2d: \ + unexpected("BlackTable", a0); \ + goto eol2d; \ + badWhite2d: \ + unexpected("WhiteTable", a0); \ + goto eol2d; \ + eof2d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ + } \ + } \ + if (RunLength) { \ + if (RunLength + a0 < lastx) { \ + /* expect a final V0 */ \ + NeedBits8(1,eof2d); \ + if (!GetBits(1)) \ + goto badMain2d; \ + ClrBits(1); \ + } \ + SETVALUE(0); \ + } \ +eol2d: \ + CLEANUP_RUNS(); \ +} while (0) +#endif /* _FAX3_ */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_fax3sm.c b/thirdparty/libtiff/tif_fax3sm.c new file mode 100644 index 00000000..822191ec --- /dev/null +++ b/thirdparty/libtiff/tif_fax3sm.c @@ -0,0 +1,1260 @@ +/* WARNING, this file was automatically generated by the + mkg3states program */ +#include "tiff.h" +#include "tif_fax3.h" + const TIFFFaxTabEnt TIFFFaxMainTable[128] = { +{12,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{5,6,2},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{5,7,3},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,6,2},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{6,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{5,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,7,3},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{4,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0} +}; + const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = { +{12,11,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2112},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2368},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,12,1984},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2240},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2496},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{12,11,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2176},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2432},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2048},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,12,2304},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2560},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7} +}; + const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = { +{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,56},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,30},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2112},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,44},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,60},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,1984},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,34},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1664},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1408},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,61},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,1024},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,768},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,62},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,38},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,512},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2496},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,12,192},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1280},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,31},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,896},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,640},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,45},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,12,448},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1536},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,41},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2048},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,51},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,59},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1152},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,63},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,2304},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,39},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,56},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,30},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2112},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,44},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,60},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,1984},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,34},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,1728},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1472},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,61},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1088},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,832},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,62},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,38},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,576},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2496},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,192},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1344},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,31},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,960},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,704},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,45},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,448},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1600},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,41},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2048},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,51},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,59},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1216},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,63},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2304},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,39},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2} +}; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_flush.c b/thirdparty/libtiff/tif_flush.c new file mode 100644 index 00000000..7ecc4d83 --- /dev/null +++ b/thirdparty/libtiff/tif_flush.c @@ -0,0 +1,74 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_flush.c,v 1.3.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +int +TIFFFlush(TIFF* tif) +{ + + if (tif->tif_mode != O_RDONLY) { + if (!TIFFFlushData(tif)) + return (0); + if ((tif->tif_flags & TIFF_DIRTYDIRECT) && + !TIFFWriteDirectory(tif)) + return (0); + } + return (1); +} + +/* + * Flush buffered data to the file. + * + * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING + * is not set, so that TIFFFlush() will proceed to write out the directory. + * The documentation says returning 1 is an error indicator, but not having + * been writing isn't exactly a an error. Hopefully this doesn't cause + * problems for other people. + */ +int +TIFFFlushData(TIFF* tif) +{ + if ((tif->tif_flags & TIFF_BEENWRITING) == 0) + return (0); + if (tif->tif_flags & TIFF_POSTENCODE) { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) + return (0); + } + return (TIFFFlushData1(tif)); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_getimage.c b/thirdparty/libtiff/tif_getimage.c new file mode 100644 index 00000000..38455fbc --- /dev/null +++ b/thirdparty/libtiff/tif_getimage.c @@ -0,0 +1,2676 @@ +/* $Id: tif_getimage.c,v 1.63.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Read and return a packed RGBA image. + */ +#include "tiffiop.h" +#include + +static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); +static int PickContigCase(TIFFRGBAImage*); +static int PickSeparateCase(TIFFRGBAImage*); +static const char photoTag[] = "PhotometricInterpretation"; + +/* + * Helper constants used in Orientation tag handling + */ +#define FLIP_VERTICALLY 0x01 +#define FLIP_HORIZONTALLY 0x02 + +/* + * Color conversion constants. We will define display types here. + */ + +TIFFDisplay display_sRGB = { + { /* XYZ -> luminance matrix */ + { 3.2410F, -1.5374F, -0.4986F }, + { -0.9692F, 1.8760F, 0.0416F }, + { 0.0556F, -0.2040F, 1.0570F } + }, + 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */ + 255, 255, 255, /* Pixel values for ref. white */ + 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */ + 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */ +}; + +/* + * Check the image to see if TIFFReadRGBAImage can deal with it. + * 1/0 is returned according to whether or not the image can + * be handled. If 0 is returned, emsg contains the reason + * why it is being rejected. + */ +int +TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) +{ + TIFFDirectory* td = &tif->tif_dir; + uint16 photometric; + int colorchannels; + + if (!tif->tif_decodestatus) { + sprintf(emsg, "Sorry, requested compression method is not configured"); + return (0); + } + switch (td->td_bitspersample) { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + sprintf(emsg, "Sorry, can not handle images with %d-bit samples", + td->td_bitspersample); + return (0); + } + colorchannels = td->td_samplesperpixel - td->td_extrasamples; + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { + switch (colorchannels) { + case 1: + photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + photometric = PHOTOMETRIC_RGB; + break; + default: + sprintf(emsg, "Missing needed %s tag", photoTag); + return (0); + } + } + switch (photometric) { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + if (td->td_planarconfig == PLANARCONFIG_CONTIG + && td->td_samplesperpixel != 1 + && td->td_bitspersample < 8 ) { + sprintf(emsg, + "Sorry, can not handle contiguous data with %s=%d, " + "and %s=%d and Bits/Sample=%d", + photoTag, photometric, + "Samples/pixel", td->td_samplesperpixel, + td->td_bitspersample); + return (0); + } + /* + * We should likely validate that any extra samples are either + * to be ignored, or are alpha, and if alpha we should try to use + * them. But for now we won't bother with this. + */ + break; + case PHOTOMETRIC_YCBCR: + /* + * TODO: if at all meaningful and useful, make more complete + * support check here, or better still, refactor to let supporting + * code decide whether there is support and what meaningfull + * error to return + */ + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) { + sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + return (0); + } + break; + case PHOTOMETRIC_SEPARATED: + { + uint16 inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) { + sprintf(emsg, + "Sorry, can not handle separated image with %s=%d", + "InkSet", inkset); + return 0; + } + if (td->td_samplesperpixel < 4) { + sprintf(emsg, + "Sorry, can not handle separated image with %s=%d", + "Samples/pixel", td->td_samplesperpixel); + return 0; + } + break; + } + case PHOTOMETRIC_LOGL: + if (td->td_compression != COMPRESSION_SGILOG) { + sprintf(emsg, "Sorry, LogL data must have %s=%d", + "Compression", COMPRESSION_SGILOG); + return (0); + } + break; + case PHOTOMETRIC_LOGLUV: + if (td->td_compression != COMPRESSION_SGILOG && + td->td_compression != COMPRESSION_SGILOG24) { + sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); + return (0); + } + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", + "Planarconfiguration", td->td_planarconfig); + return (0); + } + break; + case PHOTOMETRIC_CIELAB: + break; + default: + sprintf(emsg, "Sorry, can not handle image with %s=%d", + photoTag, photometric); + return (0); + } + return (1); +} + +void +TIFFRGBAImageEnd(TIFFRGBAImage* img) +{ + if (img->Map) + _TIFFfree(img->Map), img->Map = NULL; + if (img->BWmap) + _TIFFfree(img->BWmap), img->BWmap = NULL; + if (img->PALmap) + _TIFFfree(img->PALmap), img->PALmap = NULL; + if (img->ycbcr) + _TIFFfree(img->ycbcr), img->ycbcr = NULL; + if (img->cielab) + _TIFFfree(img->cielab), img->cielab = NULL; + if( img->redcmap ) { + _TIFFfree( img->redcmap ); + _TIFFfree( img->greencmap ); + _TIFFfree( img->bluecmap ); + } +} + +static int +isCCITTCompression(TIFF* tif) +{ + uint16 compress; + TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); + return (compress == COMPRESSION_CCITTFAX3 || + compress == COMPRESSION_CCITTFAX4 || + compress == COMPRESSION_CCITTRLE || + compress == COMPRESSION_CCITTRLEW); +} + +int +TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) +{ + uint16* sampleinfo; + uint16 extrasamples; + uint16 planarconfig; + uint16 compress; + int colorchannels; + uint16 *red_orig, *green_orig, *blue_orig; + int n_color; + + /* Initialize to normal values */ + img->row_offset = 0; + img->col_offset = 0; + img->redcmap = NULL; + img->greencmap = NULL; + img->bluecmap = NULL; + img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */ + + img->tif = tif; + img->stoponerr = stop; + TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); + switch (img->bitspersample) { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + sprintf(emsg, "Sorry, can not handle images with %d-bit samples", + img->bitspersample); + return (0); + } + img->alpha = 0; + TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extrasamples, &sampleinfo); + if (extrasamples >= 1) + { + switch (sampleinfo[0]) { + case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without */ + if (img->samplesperpixel > 3) /* correct info about alpha channel */ + img->alpha = EXTRASAMPLE_ASSOCALPHA; + break; + case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ + case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ + img->alpha = sampleinfo[0]; + break; + } + } + +#ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA + if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) + img->photometric = PHOTOMETRIC_MINISWHITE; + + if( extrasamples == 0 + && img->samplesperpixel == 4 + && img->photometric == PHOTOMETRIC_RGB ) + { + img->alpha = EXTRASAMPLE_ASSOCALPHA; + extrasamples = 1; + } +#endif + + colorchannels = img->samplesperpixel - extrasamples; + TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); + TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { + switch (colorchannels) { + case 1: + if (isCCITTCompression(tif)) + img->photometric = PHOTOMETRIC_MINISWHITE; + else + img->photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + img->photometric = PHOTOMETRIC_RGB; + break; + default: + sprintf(emsg, "Missing needed %s tag", photoTag); + return (0); + } + } + switch (img->photometric) { + case PHOTOMETRIC_PALETTE: + if (!TIFFGetField(tif, TIFFTAG_COLORMAP, + &red_orig, &green_orig, &blue_orig)) { + sprintf(emsg, "Missing required \"Colormap\" tag"); + return (0); + } + + /* copy the colormaps so we can modify them */ + n_color = (1L << img->bitspersample); + img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + if( !img->redcmap || !img->greencmap || !img->bluecmap ) { + sprintf(emsg, "Out of memory for colormap copy"); + return (0); + } + + _TIFFmemcpy( img->redcmap, red_orig, n_color * 2 ); + _TIFFmemcpy( img->greencmap, green_orig, n_color * 2 ); + _TIFFmemcpy( img->bluecmap, blue_orig, n_color * 2 ); + + /* fall thru... */ + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (planarconfig == PLANARCONFIG_CONTIG + && img->samplesperpixel != 1 + && img->bitspersample < 8 ) { + sprintf(emsg, + "Sorry, can not handle contiguous data with %s=%d, " + "and %s=%d and Bits/Sample=%d", + photoTag, img->photometric, + "Samples/pixel", img->samplesperpixel, + img->bitspersample); + return (0); + } + break; + case PHOTOMETRIC_YCBCR: + /* It would probably be nice to have a reality check here. */ + if (planarconfig == PLANARCONFIG_CONTIG) + /* can rely on libjpeg to convert to RGB */ + /* XXX should restore current state on exit */ + switch (compress) { + case COMPRESSION_JPEG: + /* + * TODO: when complete tests verify complete desubsampling + * and YCbCr handling, remove use of TIFFTAG_JPEGCOLORMODE in + * favor of tif_getimage.c native handling + */ + TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + img->photometric = PHOTOMETRIC_RGB; + break; + default: + /* do nothing */; + break; + } + /* + * TODO: if at all meaningful and useful, make more complete + * support check here, or better still, refactor to let supporting + * code decide whether there is support and what meaningfull + * error to return + */ + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) { + sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + return (0); + } + break; + case PHOTOMETRIC_SEPARATED: + { + uint16 inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "InkSet", inkset); + return (0); + } + if (img->samplesperpixel < 4) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "Samples/pixel", img->samplesperpixel); + return (0); + } + } + break; + case PHOTOMETRIC_LOGL: + if (compress != COMPRESSION_SGILOG) { + sprintf(emsg, "Sorry, LogL data must have %s=%d", + "Compression", COMPRESSION_SGILOG); + return (0); + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_LOGLUV: + if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) { + sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); + return (0); + } + if (planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", + "Planarconfiguration", planarconfig); + return (0); + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_RGB; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_CIELAB: + break; + default: + sprintf(emsg, "Sorry, can not handle image with %s=%d", + photoTag, img->photometric); + return (0); + } + img->Map = NULL; + img->BWmap = NULL; + img->PALmap = NULL; + img->ycbcr = NULL; + img->cielab = NULL; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); + TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); + img->isContig = + !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); + if (img->isContig) { + if (!PickContigCase(img)) { + sprintf(emsg, "Sorry, can not handle image"); + return 0; + } + } else { + if (!PickSeparateCase(img)) { + sprintf(emsg, "Sorry, can not handle image"); + return 0; + } + } + return 1; +} + +int +TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + if (img->get == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup"); + return (0); + } + if (img->put.any == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), + "No \"put\" routine setupl; probably can not handle image format"); + return (0); + } + return (*img->get)(img, raster, w, h); +} + +/* + * Read the specified image into an ABGR-format rastertaking in account + * specified orientation. + */ +int +TIFFReadRGBAImageOriented(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, + int orientation, int stop) +{ + char emsg[1024] = ""; + TIFFRGBAImage img; + int ok; + + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) { + img.req_orientation = orientation; + /* XXX verify rwidth and rheight against width and height */ + ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, + rwidth, img.height); + TIFFRGBAImageEnd(&img); + } else { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); + ok = 0; + } + return (ok); +} + +/* + * Read the specified image into an ABGR-format raster. Use bottom left + * origin for raster by default. + */ +int +TIFFReadRGBAImage(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, int stop) +{ + return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster, + ORIENTATION_BOTLEFT, stop); +} + +static int +setorientation(TIFFRGBAImage* img) +{ + switch (img->orientation) { + case ORIENTATION_TOPLEFT: + case ORIENTATION_LEFTTOP: + if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_TOPRIGHT: + case ORIENTATION_RIGHTTOP: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_BOTRIGHT: + case ORIENTATION_RIGHTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + case ORIENTATION_BOTLEFT: + case ORIENTATION_LEFTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + default: /* NOTREACHED */ + return 0; + } +} + +/* + * Get an tile-organized image that has + * PlanarConfiguration contiguous if SamplesPerPixel > 1 + * or + * SamplesPerPixel == 1 + */ +static int +gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileContigRoutine put = img->put.contig; + uint32 col, row, y, rowstoread; + uint32 pos; + uint32 tw, th; + unsigned char* buf; + int32 fromskew, toskew; + uint32 nrow; + int ret = 1, flip; + + buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif)); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + _TIFFmemset(buf, 0, TIFFTileSize(tif)); + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(tw + w); + } + else { + y = 0; + toskew = -(int32)(tw - w); + } + + for (row = 0; row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + for (col = 0; col < w; col += tw) + { + if (TIFFReadTile(tif, buf, col+img->col_offset, + row+img->row_offset, 0, 0) < 0 && img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); + + if (col + tw > w) + { + /* + * Tile is clipped horizontally. Calculate + * visible portion and skewing factors. + */ + uint32 npix = w - col; + fromskew = tw - npix; + (*put)(img, raster+y*w+col, col, y, + npix, nrow, fromskew, toskew + fromskew, buf + pos); + } + else + { + (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos); + } + } + + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + _TIFFfree(buf); + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + return (ret); +} + +/* + * Get an tile-organized image that has + * SamplesPerPixel > 1 + * PlanarConfiguration separated + * We assume that all such images are RGB. + */ +static int +gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileSeparateRoutine put = img->put.separate; + uint32 col, row, y, rowstoread; + uint32 pos; + uint32 tw, th; + unsigned char* buf; + unsigned char* p0; + unsigned char* p1; + unsigned char* p2; + unsigned char* pa; + tsize_t tilesize; + int32 fromskew, toskew; + int alpha = img->alpha; + uint32 nrow; + int ret = 1, flip; + + tilesize = TIFFTileSize(tif); + buf = (unsigned char*) _TIFFmalloc((alpha?4:3)*tilesize); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + _TIFFmemset(buf, 0, (alpha?4:3)*tilesize); + p0 = buf; + p1 = p0 + tilesize; + p2 = p1 + tilesize; + pa = (alpha?(p2+tilesize):NULL); + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(tw + w); + } + else { + y = 0; + toskew = -(int32)(tw - w); + } + + for (row = 0; row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + for (col = 0; col < w; col += tw) + { + if (TIFFReadTile(tif, p0, col+img->col_offset, + row+img->row_offset,0,0) < 0 && img->stoponerr) + { + ret = 0; + break; + } + if (TIFFReadTile(tif, p1, col+img->col_offset, + row+img->row_offset,0,1) < 0 && img->stoponerr) + { + ret = 0; + break; + } + if (TIFFReadTile(tif, p2, col+img->col_offset, + row+img->row_offset,0,2) < 0 && img->stoponerr) + { + ret = 0; + break; + } + if (alpha) + { + if (TIFFReadTile(tif,pa,col+img->col_offset, + row+img->row_offset,0,3) < 0 && img->stoponerr) + { + ret = 0; + break; + } + } + + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); + + if (col + tw > w) + { + /* + * Tile is clipped horizontally. Calculate + * visible portion and skewing factors. + */ + uint32 npix = w - col; + fromskew = tw - npix; + (*put)(img, raster+y*w+col, col, y, + npix, nrow, fromskew, toskew + fromskew, + p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); + } else { + (*put)(img, raster+y*w+col, col, y, + tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); + } + } + + y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + _TIFFfree(buf); + return (ret); +} + +/* + * Get a strip-organized image that has + * PlanarConfiguration contiguous if SamplesPerPixel > 1 + * or + * SamplesPerPixel == 1 + */ +static int +gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileContigRoutine put = img->put.contig; + uint32 row, y, nrow, nrowsub, rowstoread; + uint32 pos; + unsigned char* buf; + uint32 rowsperstrip; + uint16 subsamplinghor,subsamplingver; + uint32 imagewidth = img->width; + tsize_t scanline; + int32 fromskew, toskew; + int ret = 1, flip; + + buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif)); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); + return (0); + } + _TIFFmemset(buf, 0, TIFFStripSize(tif)); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(w + w); + } else { + y = 0; + toskew = -(int32)(w - w); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); + scanline = TIFFNewScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + nrowsub = nrow; + if ((nrowsub%subsamplingver)!=0) + nrowsub+=subsamplingver-nrowsub%subsamplingver; + if (TIFFReadEncodedStrip(tif, + TIFFComputeStrip(tif,row+img->row_offset, 0), + buf, + ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos); + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + _TIFFfree(buf); + return (ret); +} + +/* + * Get a strip-organized image with + * SamplesPerPixel > 1 + * PlanarConfiguration separated + * We assume that all such images are RGB. + */ +static int +gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileSeparateRoutine put = img->put.separate; + unsigned char *buf; + unsigned char *p0, *p1, *p2, *pa; + uint32 row, y, nrow, rowstoread; + uint32 pos; + tsize_t scanline; + uint32 rowsperstrip, offset_row; + uint32 imagewidth = img->width; + tsize_t stripsize; + int32 fromskew, toskew; + int alpha = img->alpha; + int ret = 1, flip; + + stripsize = TIFFStripSize(tif); + p0 = buf = (unsigned char *)_TIFFmalloc((alpha?4:3)*stripsize); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + _TIFFmemset(buf, 0, (alpha?4:3)*stripsize); + p1 = p0 + stripsize; + p2 = p1 + stripsize; + pa = (alpha?(p2+stripsize):NULL); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(w + w); + } + else { + y = 0; + toskew = -(int32)(w - w); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + offset_row = row + img->row_offset; + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), + p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), + p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), + p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + if (alpha) + { + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 3), + pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos, + p2 + pos, (alpha?(pa+pos):NULL)); + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + _TIFFfree(buf); + return (ret); +} + +/* + * The following routines move decoded data returned + * from the TIFF library into rasters filled with packed + * ABGR pixels (i.e. suitable for passing to lrecwrite.) + * + * The routines have been created according to the most + * important cases and optimized. PickContigCase and + * PickSeparateCase analyze the parameters and select + * the appropriate "get" and "put" routine to use. + */ +#define REPEAT8(op) REPEAT4(op); REPEAT4(op) +#define REPEAT4(op) REPEAT2(op); REPEAT2(op) +#define REPEAT2(op) op; op +#define CASE8(x,op) \ + switch (x) { \ + case 7: op; case 6: op; case 5: op; \ + case 4: op; case 3: op; case 2: op; \ + case 1: op; \ + } +#define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; } +#define NOP + +#define UNROLL8(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 8; _x -= 8) { \ + op1; \ + REPEAT8(op2); \ + } \ + if (_x > 0) { \ + op1; \ + CASE8(_x,op2); \ + } \ +} +#define UNROLL4(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 4; _x -= 4) { \ + op1; \ + REPEAT4(op2); \ + } \ + if (_x > 0) { \ + op1; \ + CASE4(_x,op2); \ + } \ +} +#define UNROLL2(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 2; _x -= 2) { \ + op1; \ + REPEAT2(op2); \ + } \ + if (_x) { \ + op1; \ + op2; \ + } \ +} + +#define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; } +#define SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; } + +#define A1 (((uint32)0xffL)<<24) +#define PACK(r,g,b) \ + ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1) +#define PACK4(r,g,b,a) \ + ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24)) +#define W2B(v) (((v)>>8)&0xff) +#define PACKW(r,g,b) \ + ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1) +#define PACKW4(r,g,b,a) \ + ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) + +#define DECLAREContigPutFunc(name) \ +static void name(\ + TIFFRGBAImage* img, \ + uint32* cp, \ + uint32 x, uint32 y, \ + uint32 w, uint32 h, \ + int32 fromskew, int32 toskew, \ + unsigned char* pp \ +) + +/* + * 8-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put8bitcmaptile) +{ + uint32** PALmap = img->PALmap; + int samplesperpixel = img->samplesperpixel; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + { + *cp++ = PALmap[*pp][0]; + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 4-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put4bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 2; + while (h-- > 0) { + uint32* bw; + UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 2-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put2bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 4; + while (h-- > 0) { + uint32* bw; + UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 1-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put1bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 8; + while (h-- > 0) { + uint32* bw; + UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(putgreytile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + { + *cp++ = BWmap[*pp][0]; + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put16bitbwtile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + uint16 *wp = (uint16 *) pp; + + for (x = w; x-- > 0;) + { + /* use high order byte of 16bit value */ + + *cp++ = BWmap[*wp >> 8][0]; + pp += 2 * samplesperpixel; + wp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 1-bit bilevel => colormap/RGB + */ +DECLAREContigPutFunc(put1bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 8; + while (h-- > 0) { + uint32* bw; + UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 2-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put2bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 4; + while (h-- > 0) { + uint32* bw; + UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 4-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put4bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 2; + while (h-- > 0) { + uint32* bw; + UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples, no Map => RGB + */ +DECLAREContigPutFunc(putRGBcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + *cp++ = PACK(pp[0], pp[1], pp[2]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples => RGBA w/ associated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBAAcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples => RGBA w/ unassociated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBUAcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + uint32 r, g, b, a; + for (x = w; x-- > 0;) { + a = pp[3]; + r = (a*pp[0] + 127) / 255; + g = (a*pp[1] + 127) / 255; + b = (a*pp[2] + 127) / 255; + *cp++ = PACK4(r,g,b,a); + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit packed samples => RGB + */ +DECLAREContigPutFunc(putRGBcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACKW(wp[0],wp[1],wp[2]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 16-bit packed samples => RGBA w/ associated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBAAcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACKW4(wp[0],wp[1],wp[2],wp[3]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 16-bit packed samples => RGBA w/ unassociated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBUAcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + uint32 r,g,b,a; + for (x = w; x-- > 0;) { + a = W2B(wp[3]); + r = (a*W2B(wp[0]) + 127) / 255; + g = (a*W2B(wp[1]) + 127) / 255; + b = (a*W2B(wp[2]) + 127) / 255; + *cp++ = PACK4(r,g,b,a); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 8-bit packed CMYK samples w/o Map => RGB + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 r, g, b, k; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + *cp++ = PACK(r, g, b); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed CMYK samples w/Map => RGB + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) +{ + int samplesperpixel = img->samplesperpixel; + TIFFRGBValue* Map = img->Map; + uint16 r, g, b, k; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + *cp++ = PACK(Map[r], Map[g], Map[b]); + pp += samplesperpixel; + } + pp += fromskew; + cp += toskew; + } +} + +#define DECLARESepPutFunc(name) \ +static void name(\ + TIFFRGBAImage* img,\ + uint32* cp,\ + uint32 x, uint32 y, \ + uint32 w, uint32 h,\ + int32 fromskew, int32 toskew,\ + unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a\ +) + +/* + * 8-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate8bittile) +{ + (void) img; (void) x; (void) y; (void) a; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate8bittile) +{ + (void) img; (void) x; (void) y; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ unassociated alpha + */ +DECLARESepPutFunc(putRGBUAseparate8bittile) +{ + (void) img; (void) y; + while (h-- > 0) { + uint32 rv, gv, bv, av; + for (x = w; x-- > 0;) { + av = *a++; + rv = (av* *r++ + 127) / 255; + gv = (av* *g++ + 127) / 255; + bv = (av* *b++ + 127) / 255; + *cp++ = PACK4(rv,gv,bv,av); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + (void) img; (void) y; (void) a; + while (h-- > 0) { + for (x = 0; x < w; x++) + *cp++ = PACKW(*wr++,*wg++,*wb++); + SKEW(wr, wg, wb, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + uint16 *wa = (uint16*) a; + (void) img; (void) y; + while (h-- > 0) { + for (x = 0; x < w; x++) + *cp++ = PACKW4(*wr++,*wg++,*wb++,*wa++); + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGBA w/ unassociated alpha + */ +DECLARESepPutFunc(putRGBUAseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + uint16 *wa = (uint16*) a; + (void) img; (void) y; + while (h-- > 0) { + uint32 r,g,b,a; + for (x = w; x-- > 0;) { + a = W2B(*wa++); + r = (a*W2B(*wr++) + 127) / 255; + g = (a*W2B(*wg++) + 127) / 255; + b = (a*W2B(*wb++) + 127) / 255; + *cp++ = PACK4(r,g,b,a); + } + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } +} + +/* + * 8-bit packed CIE L*a*b 1976 samples => RGB + */ +DECLAREContigPutFunc(putcontig8bitCIELab) +{ + float X, Y, Z; + uint32 r, g, b; + (void) y; + fromskew *= 3; + while (h-- > 0) { + for (x = w; x-- > 0;) { + TIFFCIELabToXYZ(img->cielab, + (unsigned char)pp[0], + (signed char)pp[1], + (signed char)pp[2], + &X, &Y, &Z); + TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); + *cp++ = PACK(r, g, b); + pp += 3; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * YCbCr -> RGB conversion and packing routines. + */ + +#define YCbCrtoRGB(dst, Y) { \ + uint32 r, g, b; \ + TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \ + dst = PACK(r, g, b); \ +} + +/* + * 8-bit packed YCbCr samples => RGB + * This function is generic for different sampling sizes, + * and can handle blocks sizes that aren't multiples of the + * sampling size. However, it is substantially less optimized + * than the specific sampling cases. It is used as a fallback + * for difficult blocks. + */ +#ifdef notdef +static void putcontig8bitYCbCrGenericTile( + TIFFRGBAImage* img, + uint32* cp, + uint32 x, uint32 y, + uint32 w, uint32 h, + int32 fromskew, int32 toskew, + unsigned char* pp, + int h_group, + int v_group ) + +{ + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + int32 Cb, Cr; + int group_size = v_group * h_group + 2; + + (void) y; + fromskew = (fromskew * group_size) / h_group; + + for( yy = 0; yy < h; yy++ ) + { + unsigned char *pp_line; + int y_line_group = yy / v_group; + int y_remainder = yy - y_line_group * v_group; + + pp_line = pp + v_line_group * + + + for( xx = 0; xx < w; xx++ ) + { + Cb = pp + } + } + for (; h >= 4; h -= 4) { + x = w>>2; + do { + Cb = pp[16]; + Cr = pp[17]; + + YCbCrtoRGB(cp [0], pp[ 0]); + YCbCrtoRGB(cp [1], pp[ 1]); + YCbCrtoRGB(cp [2], pp[ 2]); + YCbCrtoRGB(cp [3], pp[ 3]); + YCbCrtoRGB(cp1[0], pp[ 4]); + YCbCrtoRGB(cp1[1], pp[ 5]); + YCbCrtoRGB(cp1[2], pp[ 6]); + YCbCrtoRGB(cp1[3], pp[ 7]); + YCbCrtoRGB(cp2[0], pp[ 8]); + YCbCrtoRGB(cp2[1], pp[ 9]); + YCbCrtoRGB(cp2[2], pp[10]); + YCbCrtoRGB(cp2[3], pp[11]); + YCbCrtoRGB(cp3[0], pp[12]); + YCbCrtoRGB(cp3[1], pp[13]); + YCbCrtoRGB(cp3[2], pp[14]); + YCbCrtoRGB(cp3[3], pp[15]); + + cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + pp += 18; + } while (--x); + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } +} +#endif + +/* + * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr44tile) +{ + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + + (void) y; + /* adjust fromskew */ + fromskew = (fromskew * 18) / 4; + if ((h & 3) == 0 && (w & 3) == 0) { + for (; h >= 4; h -= 4) { + x = w>>2; + do { + int32 Cb = pp[16]; + int32 Cr = pp[17]; + + YCbCrtoRGB(cp [0], pp[ 0]); + YCbCrtoRGB(cp [1], pp[ 1]); + YCbCrtoRGB(cp [2], pp[ 2]); + YCbCrtoRGB(cp [3], pp[ 3]); + YCbCrtoRGB(cp1[0], pp[ 4]); + YCbCrtoRGB(cp1[1], pp[ 5]); + YCbCrtoRGB(cp1[2], pp[ 6]); + YCbCrtoRGB(cp1[3], pp[ 7]); + YCbCrtoRGB(cp2[0], pp[ 8]); + YCbCrtoRGB(cp2[1], pp[ 9]); + YCbCrtoRGB(cp2[2], pp[10]); + YCbCrtoRGB(cp2[3], pp[11]); + YCbCrtoRGB(cp3[0], pp[12]); + YCbCrtoRGB(cp3[1], pp[13]); + YCbCrtoRGB(cp3[2], pp[14]); + YCbCrtoRGB(cp3[3], pp[15]); + + cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + pp += 18; + } while (--x); + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[16]; + int32 Cr = pp[17]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; cp2 += x; cp3 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; cp2 += 4; cp3 += 4; + x -= 4; + } + pp += 18; + } + if (h <= 4) + break; + h -= 4; + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr42tile) +{ + uint32* cp1 = cp+w+toskew; + int32 incr = 2*toskew+w; + + (void) y; + fromskew = (fromskew * 10) / 4; + if ((h & 3) == 0 && (w & 1) == 0) { + for (; h >= 2; h -= 2) { + x = w>>2; + do { + int32 Cb = pp[8]; + int32 Cr = pp[9]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp [2], pp[2]); + YCbCrtoRGB(cp [3], pp[3]); + YCbCrtoRGB(cp1[0], pp[4]); + YCbCrtoRGB(cp1[1], pp[5]); + YCbCrtoRGB(cp1[2], pp[6]); + YCbCrtoRGB(cp1[3], pp[7]); + + cp += 4, cp1 += 4; + pp += 10; + } while (--x); + cp += incr, cp1 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[8]; + int32 Cr = pp[9]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; + x -= 4; + } + pp += 10; + } + if (h <= 2) + break; + h -= 2; + cp += incr, cp1 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr41tile) +{ + (void) y; + /* XXX adjust fromskew */ + do { + x = w>>2; + do { + int32 Cb = pp[4]; + int32 Cr = pp[5]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp [2], pp[2]); + YCbCrtoRGB(cp [3], pp[3]); + + cp += 4; + pp += 6; + } while (--x); + + if( (w&3) != 0 ) + { + int32 Cb = pp[4]; + int32 Cr = pp[5]; + + switch( (w&3) ) { + case 3: YCbCrtoRGB(cp [2], pp[2]); + case 2: YCbCrtoRGB(cp [1], pp[1]); + case 1: YCbCrtoRGB(cp [0], pp[0]); + case 0: break; + } + + cp += (w&3); + pp += 6; + } + + cp += toskew; + pp += fromskew; + } while (--h); + +} + +/* + * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr22tile) +{ + uint32* cp2; + (void) y; + fromskew = (fromskew / 2) * 6; + cp2 = cp+w+toskew; + while (h>=2) { + x = w; + while (x>=2) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp2[0], pp[2]); + YCbCrtoRGB(cp2[1], pp[3]); + cp += 2; + cp2 += 2; + pp += 6; + x -= 2; + } + if (x==1) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp2[0], pp[2]); + cp ++ ; + cp2 ++ ; + pp += 6; + } + cp += toskew*2+w; + cp2 += toskew*2+w; + pp += fromskew; + h-=2; + } + if (h==1) { + x = w; + while (x>=2) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + cp += 2; + cp2 += 2; + pp += 6; + x -= 2; + } + if (x==1) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr21tile) +{ + (void) y; + fromskew = (fromskew * 4) / 2; + do { + x = w>>1; + do { + int32 Cb = pp[2]; + int32 Cr = pp[3]; + + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + + cp += 2; + pp += 4; + } while (--x); + + if( (w&1) != 0 ) + { + int32 Cb = pp[2]; + int32 Cr = pp[3]; + + YCbCrtoRGB(cp[0], pp[0]); + + cp += 1; + pp += 4; + } + + cp += toskew; + pp += fromskew; + } while (--h); +} + +/* + * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr12tile) +{ + uint32* cp2; + (void) y; + fromskew = (fromskew / 2) * 4; + cp2 = cp+w+toskew; + while (h>=2) { + x = w; + do { + uint32 Cb = pp[2]; + uint32 Cr = pp[3]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp2[0], pp[1]); + cp ++; + cp2 ++; + pp += 4; + } while (--x); + cp += toskew*2+w; + cp2 += toskew*2+w; + pp += fromskew; + h-=2; + } + if (h==1) { + x = w; + do { + uint32 Cb = pp[2]; + uint32 Cr = pp[3]; + YCbCrtoRGB(cp[0], pp[0]); + cp ++; + pp += 4; + } while (--x); + } +} + +/* + * 8-bit packed YCbCr samples w/ no subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr11tile) +{ + (void) y; + fromskew *= 3; + do { + x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ + do { + int32 Cb = pp[1]; + int32 Cr = pp[2]; + + YCbCrtoRGB(*cp++, pp[0]); + + pp += 3; + } while (--x); + cp += toskew; + pp += fromskew; + } while (--h); +} + +/* + * 8-bit packed YCbCr samples w/ no subsampling => RGB + */ +DECLARESepPutFunc(putseparate8bitYCbCr11tile) +{ + (void) y; + (void) a; + /* TODO: naming of input vars is still off, change obfuscating declaration inside define, or resolve obfuscation */ + while (h-- > 0) { + x = w; + do { + uint32 dr, dg, db; + TIFFYCbCrtoRGB(img->ycbcr,*r++,*g++,*b++,&dr,&dg,&db); + *cp++ = PACK(dr,dg,db); + } while (--x); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} +#undef YCbCrtoRGB + +static int +initYCbCrConversion(TIFFRGBAImage* img) +{ + static char module[] = "initYCbCrConversion"; + + float *luma, *refBlackWhite; + + if (img->ycbcr == NULL) { + img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( + TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)) + + 4*256*sizeof (TIFFRGBValue) + + 2*256*sizeof (int) + + 3*256*sizeof (int32) + ); + if (img->ycbcr == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, module, + "No space for YCbCr->RGB conversion state"); + return (0); + } + } + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma); + TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE, + &refBlackWhite); + if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0) + return(0); + return (1); +} + +static tileContigRoutine +initCIELabConversion(TIFFRGBAImage* img) +{ + static char module[] = "initCIELabConversion"; + + float *whitePoint; + float refWhite[3]; + + if (!img->cielab) { + img->cielab = (TIFFCIELabToRGB *) + _TIFFmalloc(sizeof(TIFFCIELabToRGB)); + if (!img->cielab) { + TIFFErrorExt(img->tif->tif_clientdata, module, + "No space for CIE L*a*b*->RGB conversion state."); + return NULL; + } + } + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint); + refWhite[1] = 100.0F; + refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1]; + refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1]) + / whitePoint[1] * refWhite[1]; + if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) { + TIFFErrorExt(img->tif->tif_clientdata, module, + "Failed to initialize CIE L*a*b*->RGB conversion state."); + _TIFFfree(img->cielab); + return NULL; + } + + return putcontig8bitCIELab; +} + +/* + * Greyscale images with less than 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table + * is setup so that put*bwtile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +static int +makebwmap(TIFFRGBAImage* img) +{ + TIFFRGBValue* Map = img->Map; + int bitspersample = img->bitspersample; + int nsamples = 8 / bitspersample; + int i; + uint32* p; + + if( nsamples == 0 ) + nsamples = 1; + + img->BWmap = (uint32**) _TIFFmalloc( + 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); + if (img->BWmap == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for B&W mapping table"); + return (0); + } + p = (uint32*)(img->BWmap + 256); + for (i = 0; i < 256; i++) { + TIFFRGBValue c; + img->BWmap[i] = p; + switch (bitspersample) { +#define GREY(x) c = Map[x]; *p++ = PACK(c,c,c); + case 1: + GREY(i>>7); + GREY((i>>6)&1); + GREY((i>>5)&1); + GREY((i>>4)&1); + GREY((i>>3)&1); + GREY((i>>2)&1); + GREY((i>>1)&1); + GREY(i&1); + break; + case 2: + GREY(i>>6); + GREY((i>>4)&3); + GREY((i>>2)&3); + GREY(i&3); + break; + case 4: + GREY(i>>4); + GREY(i&0xf); + break; + case 8: + case 16: + GREY(i); + break; + } +#undef GREY + } + return (1); +} + +/* + * Construct a mapping table to convert from the range + * of the data samples to [0,255] --for display. This + * process also handles inverting B&W images when needed. + */ +static int +setupMap(TIFFRGBAImage* img) +{ + int32 x, range; + + range = (int32)((1L<bitspersample)-1); + + /* treat 16 bit the same as eight bit */ + if( img->bitspersample == 16 ) + range = (int32) 255; + + img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); + if (img->Map == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), + "No space for photometric conversion table"); + return (0); + } + if (img->photometric == PHOTOMETRIC_MINISWHITE) { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range); + } else { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue) ((x * 255) / range); + } + if (img->bitspersample <= 16 && + (img->photometric == PHOTOMETRIC_MINISBLACK || + img->photometric == PHOTOMETRIC_MINISWHITE)) { + /* + * Use photometric mapping table to construct + * unpacking tables for samples <= 8 bits. + */ + if (!makebwmap(img)) + return (0); + /* no longer need Map, free it */ + _TIFFfree(img->Map), img->Map = NULL; + } + return (1); +} + +static int +checkcmap(TIFFRGBAImage* img) +{ + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + long n = 1L<bitspersample; + + while (n-- > 0) + if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) + return (16); + return (8); +} + +static void +cvtcmap(TIFFRGBAImage* img) +{ + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + long i; + + for (i = (1L<bitspersample)-1; i >= 0; i--) { +#define CVT(x) ((uint16)((x)>>8)) + r[i] = CVT(r[i]); + g[i] = CVT(g[i]); + b[i] = CVT(b[i]); +#undef CVT + } +} + +/* + * Palette images with <= 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table + * is setup so that put*cmaptile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +static int +makecmap(TIFFRGBAImage* img) +{ + int bitspersample = img->bitspersample; + int nsamples = 8 / bitspersample; + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + uint32 *p; + int i; + + img->PALmap = (uint32**) _TIFFmalloc( + 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); + if (img->PALmap == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for Palette mapping table"); + return (0); + } + p = (uint32*)(img->PALmap + 256); + for (i = 0; i < 256; i++) { + TIFFRGBValue c; + img->PALmap[i] = p; +#define CMAP(x) c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); + switch (bitspersample) { + case 1: + CMAP(i>>7); + CMAP((i>>6)&1); + CMAP((i>>5)&1); + CMAP((i>>4)&1); + CMAP((i>>3)&1); + CMAP((i>>2)&1); + CMAP((i>>1)&1); + CMAP(i&1); + break; + case 2: + CMAP(i>>6); + CMAP((i>>4)&3); + CMAP((i>>2)&3); + CMAP(i&3); + break; + case 4: + CMAP(i>>4); + CMAP(i&0xf); + break; + case 8: + CMAP(i); + break; + } +#undef CMAP + } + return (1); +} + +/* + * Construct any mapping table used + * by the associated put routine. + */ +static int +buildMap(TIFFRGBAImage* img) +{ + switch (img->photometric) { + case PHOTOMETRIC_RGB: + case PHOTOMETRIC_YCBCR: + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8) + break; + /* fall thru... */ + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_MINISWHITE: + if (!setupMap(img)) + return (0); + break; + case PHOTOMETRIC_PALETTE: + /* + * Convert 16-bit colormap to 8-bit (unless it looks + * like an old-style 8-bit colormap). + */ + if (checkcmap(img) == 16) + cvtcmap(img); + else + TIFFWarningExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "Assuming 8-bit colormap"); + /* + * Use mapping table and colormap to construct + * unpacking tables for samples < 8 bits. + */ + if (img->bitspersample <= 8 && !makecmap(img)) + return (0); + break; + } + return (1); +} + +/* + * Select the appropriate conversion routine for packed data. + */ +static int +PickContigCase(TIFFRGBAImage* img) +{ + img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig; + img->put.contig = NULL; + switch (img->photometric) { + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + img->put.contig = putRGBAAcontig8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + img->put.contig = putRGBUAcontig8bittile; + } + else + img->put.contig = putRGBcontig8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + { + img->put.contig = putRGBAAcontig16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + img->put.contig = putRGBUAcontig16bittile; + } + else + { + img->put.contig = putRGBcontig16bittile; + } + break; + } + break; + case PHOTOMETRIC_SEPARATED: + if (buildMap(img)) { + if (img->bitspersample == 8) { + if (!img->Map) + img->put.contig = putRGBcontig8bitCMYKtile; + else + img->put.contig = putRGBcontig8bitCMYKMaptile; + } + } + break; + case PHOTOMETRIC_PALETTE: + if (buildMap(img)) { + switch (img->bitspersample) { + case 8: + img->put.contig = put8bitcmaptile; + break; + case 4: + img->put.contig = put4bitcmaptile; + break; + case 2: + img->put.contig = put2bitcmaptile; + break; + case 1: + img->put.contig = put1bitcmaptile; + break; + } + } + break; + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (buildMap(img)) { + switch (img->bitspersample) { + case 16: + img->put.contig = put16bitbwtile; + break; + case 8: + img->put.contig = putgreytile; + break; + case 4: + img->put.contig = put4bitbwtile; + break; + case 2: + img->put.contig = put2bitbwtile; + break; + case 1: + img->put.contig = put1bitbwtile; + break; + } + } + break; + case PHOTOMETRIC_YCBCR: + if (img->bitspersample == 8) + { + if (initYCbCrConversion(img)!=0) + { + /* + * The 6.0 spec says that subsampling must be + * one of 1, 2, or 4, and that vertical subsampling + * must always be <= horizontal subsampling; so + * there are only a few possibilities and we just + * enumerate the cases. + * Joris: added support for the [1,2] case, nonetheless, to accomodate + * some OJPEG files + */ + uint16 SubsamplingHor; + uint16 SubsamplingVer; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &SubsamplingHor, &SubsamplingVer); + switch ((SubsamplingHor<<4)|SubsamplingVer) { + case 0x44: + img->put.contig = putcontig8bitYCbCr44tile; + break; + case 0x42: + img->put.contig = putcontig8bitYCbCr42tile; + break; + case 0x41: + img->put.contig = putcontig8bitYCbCr41tile; + break; + case 0x22: + img->put.contig = putcontig8bitYCbCr22tile; + break; + case 0x21: + img->put.contig = putcontig8bitYCbCr21tile; + break; + case 0x12: + img->put.contig = putcontig8bitYCbCr12tile; + break; + case 0x11: + img->put.contig = putcontig8bitYCbCr11tile; + break; + } + } + } + break; + case PHOTOMETRIC_CIELAB: + if (buildMap(img)) { + if (img->bitspersample == 8) + img->put.contig = initCIELabConversion(img); + break; + } + } + return ((img->get!=NULL) && (img->put.contig!=NULL)); +} + +/* + * Select the appropriate conversion routine for unpacked data. + * + * NB: we assume that unpacked single channel data is directed + * to the "packed routines. + */ +static int +PickSeparateCase(TIFFRGBAImage* img) +{ + img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate; + img->put.separate = NULL; + switch (img->photometric) { + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + img->put.separate = putRGBAAseparate8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + img->put.separate = putRGBUAseparate8bittile; + } + else + img->put.separate = putRGBseparate8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + { + img->put.separate = putRGBAAseparate16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + img->put.separate = putRGBUAseparate16bittile; + } + else + { + img->put.separate = putRGBseparate16bittile; + } + break; + } + break; + case PHOTOMETRIC_YCBCR: + if ((img->bitspersample==8) && (img->samplesperpixel==3)) + { + if (initYCbCrConversion(img)!=0) + { + uint16 hs, vs; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); + switch ((hs<<4)|vs) { + case 0x11: + img->put.separate = putseparate8bitYCbCr11tile; + break; + /* TODO: add other cases here */ + } + } + } + break; + } + return ((img->get!=NULL) && (img->put.separate!=NULL)); +} + +/* + * Read a whole strip off data from the file, and convert to RGBA form. + * If this is the last strip, then it will only contain the portion of + * the strip that is actually within the image space. The result is + * organized in bottom to top form. + */ + + +int +TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) + +{ + char emsg[1024] = ""; + TIFFRGBAImage img; + int ok; + uint32 rowsperstrip, rows_to_read; + + if( TIFFIsTiled( tif ) ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Can't use TIFFReadRGBAStrip() with tiled file."); + return (0); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + if( (row % rowsperstrip) != 0 ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Row passed to TIFFReadRGBAStrip() must be first in a strip."); + return (0); + } + + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + + img.row_offset = row; + img.col_offset = 0; + + if( row + rowsperstrip > img.height ) + rows_to_read = img.height - row; + else + rows_to_read = rowsperstrip; + + ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read ); + + TIFFRGBAImageEnd(&img); + } else { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); + ok = 0; + } + + return (ok); +} + +/* + * Read a whole tile off data from the file, and convert to RGBA form. + * The returned RGBA data is organized from bottom to top of tile, + * and may include zeroed areas if the tile extends off the image. + */ + +int +TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) + +{ + char emsg[1024] = ""; + TIFFRGBAImage img; + int ok; + uint32 tile_xsize, tile_ysize; + uint32 read_xsize, read_ysize; + uint32 i_row; + + /* + * Verify that our request is legal - on a tile file, and on a + * tile boundary. + */ + + if( !TIFFIsTiled( tif ) ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Can't use TIFFReadRGBATile() with stripped file."); + return (0); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); + TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); + if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Row/col passed to TIFFReadRGBATile() must be top" + "left corner of a tile."); + return (0); + } + + /* + * Setup the RGBA reader. + */ + + if (!TIFFRGBAImageOK(tif, emsg) + || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); + return( 0 ); + } + + /* + * The TIFFRGBAImageGet() function doesn't allow us to get off the + * edge of the image, even to fill an otherwise valid tile. So we + * figure out how much we can read, and fix up the tile buffer to + * a full tile configuration afterwards. + */ + + if( row + tile_ysize > img.height ) + read_ysize = img.height - row; + else + read_ysize = tile_ysize; + + if( col + tile_xsize > img.width ) + read_xsize = img.width - col; + else + read_xsize = tile_xsize; + + /* + * Read the chunk of imagery. + */ + + img.row_offset = row; + img.col_offset = col; + + ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize ); + + TIFFRGBAImageEnd(&img); + + /* + * If our read was incomplete we will need to fix up the tile by + * shifting the data around as if a full tile of data is being returned. + * + * This is all the more complicated because the image is organized in + * bottom to top format. + */ + + if( read_xsize == tile_xsize && read_ysize == tile_ysize ) + return( ok ); + + for( i_row = 0; i_row < read_ysize; i_row++ ) { + memmove( raster + (tile_ysize - i_row - 1) * tile_xsize, + raster + (read_ysize - i_row - 1) * read_xsize, + read_xsize * sizeof(uint32) ); + _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, + 0, sizeof(uint32) * (tile_xsize - read_xsize) ); + } + + for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) { + _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, + 0, sizeof(uint32) * tile_xsize ); + } + + return (ok); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_jbig.c b/thirdparty/libtiff/tif_jbig.c new file mode 100644 index 00000000..c92ee3de --- /dev/null +++ b/thirdparty/libtiff/tif_jbig.c @@ -0,0 +1,385 @@ +/* $Id: tif_jbig.c,v 1.2.2.3 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * JBIG Compression Algorithm Support. + * Contributed by Lee Howard + * + */ + +#include "tiffiop.h" + +#ifdef JBIG_SUPPORT +#include "jbig.h" + +typedef struct +{ + uint32 recvparams; /* encoded Class 2 session params */ + char* subaddress; /* subaddress string */ + uint32 recvtime; /* time spend receiving in seconds */ + char* faxdcs; /* encoded fax parameters (DCS, Table 2/T.30) */ + + TIFFVGetMethod vgetparent; + TIFFVSetMethod vsetparent; +} JBIGState; + +#define GetJBIGState(tif) ((JBIGState*)(tif)->tif_data) + +#define FIELD_RECVPARAMS (FIELD_CODEC+0) +#define FIELD_SUBADDRESS (FIELD_CODEC+1) +#define FIELD_RECVTIME (FIELD_CODEC+2) +#define FIELD_FAXDCS (FIELD_CODEC+3) + +static const TIFFFieldInfo jbigFieldInfo[] = +{ + {TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, TRUE, FALSE, "FaxRecvParams"}, + {TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, FIELD_SUBADDRESS, TRUE, FALSE, "FaxSubAddress"}, + {TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, TRUE, FALSE, "FaxRecvTime"}, + {TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, FIELD_FAXDCS, TRUE, FALSE, "FaxDcs"}, +}; + +static int JBIGSetupDecode(TIFF* tif) +{ + if (TIFFNumberOfStrips(tif) != 1) + { + TIFFError("JBIG", "Multistrip images not supported in decoder"); + return 0; + } + + return 1; +} + +static int JBIGDecode(TIFF* tif, tidata_t buffer, tsize_t size, tsample_t s) +{ + struct jbg_dec_state decoder; + int decodeStatus = 0; + unsigned char* pImage = NULL; + (void) size, (void) s; + + if (isFillOrder(tif, tif->tif_dir.td_fillorder)) + { + TIFFReverseBits(tif->tif_rawdata, tif->tif_rawdatasize); + } + + jbg_dec_init(&decoder); + +#if defined(HAVE_JBG_NEWLEN) + jbg_newlen(tif->tif_rawdata, tif->tif_rawdatasize); + /* + * I do not check the return status of jbg_newlen because even if this + * function fails it does not necessarily mean that decoding the image + * will fail. It is generally only needed for received fax images + * that do not contain the actual length of the image in the BIE + * header. I do not log when an error occurs because that will cause + * problems when converting JBIG encoded TIFF's to + * PostScript. As long as the actual image length is contained in the + * BIE header jbg_dec_in should succeed. + */ +#endif /* HAVE_JBG_NEWLEN */ + + decodeStatus = jbg_dec_in(&decoder, tif->tif_rawdata, + tif->tif_rawdatasize, NULL); + if (JBG_EOK != decodeStatus) + { + /* + * XXX: JBG_EN constant was defined in pre-2.0 releases of the + * JBIG-KIT. Since the 2.0 the error reporting functions were + * changed. We will handle both cases here. + */ + TIFFError("JBIG", "Error (%d) decoding: %s", decodeStatus, +#if defined(JBG_EN) + jbg_strerror(decodeStatus, JBG_EN) +#else + jbg_strerror(decodeStatus) +#endif + ); + return 0; + } + + pImage = jbg_dec_getimage(&decoder, 0); + _TIFFmemcpy(buffer, pImage, jbg_dec_getsize(&decoder)); + jbg_dec_free(&decoder); + return 1; +} + +static int JBIGSetupEncode(TIFF* tif) +{ + if (TIFFNumberOfStrips(tif) != 1) + { + TIFFError("JBIG", "Multistrip images not supported in encoder"); + return 0; + } + + return 1; +} + +static int JBIGCopyEncodedData(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) s; + while (cc > 0) + { + tsize_t n = cc; + + if (tif->tif_rawcc + n > tif->tif_rawdatasize) + { + n = tif->tif_rawdatasize - tif->tif_rawcc; + } + + assert(n > 0); + _TIFFmemcpy(tif->tif_rawcp, pp, n); + tif->tif_rawcp += n; + tif->tif_rawcc += n; + pp += n; + cc -= n; + if (tif->tif_rawcc >= tif->tif_rawdatasize && + !TIFFFlushData1(tif)) + { + return (-1); + } + } + + return (1); +} + +static void JBIGOutputBie(unsigned char* buffer, size_t len, void *userData) +{ + TIFF* tif = (TIFF*)userData; + + if (isFillOrder(tif, tif->tif_dir.td_fillorder)) + { + TIFFReverseBits(buffer, len); + } + + JBIGCopyEncodedData(tif, buffer, len, 0); +} + +static int JBIGEncode(TIFF* tif, tidata_t buffer, tsize_t size, tsample_t s) +{ + TIFFDirectory* dir = &tif->tif_dir; + struct jbg_enc_state encoder; + + (void) size, (void) s; + + jbg_enc_init(&encoder, + dir->td_imagewidth, + dir->td_imagelength, + 1, + &buffer, + JBIGOutputBie, + tif); + /* + * jbg_enc_out does the "real" encoding. As data is encoded, + * JBIGOutputBie is called, which writes the data to the directory. + */ + jbg_enc_out(&encoder); + jbg_enc_free(&encoder); + + return 1; +} + +static void JBIGCleanup(TIFF* tif) +{ + JBIGState *sp = GetJBIGState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static void JBIGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + JBIGState* codec = GetJBIGState(tif); + (void)flags; + + if (TIFFFieldSet(tif, FIELD_RECVPARAMS)) + { + fprintf(fd, + " Fax Receive Parameters: %08lx\n", + (unsigned long)codec->recvparams); + } + + if (TIFFFieldSet(tif, FIELD_SUBADDRESS)) + { + fprintf(fd, + " Fax SubAddress: %s\n", + codec->subaddress); + } + + if (TIFFFieldSet(tif, FIELD_RECVTIME)) + { + fprintf(fd, + " Fax Receive Time: %lu secs\n", + (unsigned long)codec->recvtime); + } + + if (TIFFFieldSet(tif, FIELD_FAXDCS)) + { + fprintf(fd, + " Fax DCS: %s\n", + codec->faxdcs); + } +} + +static int JBIGVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JBIGState* codec = GetJBIGState(tif); + + switch (tag) + { + case TIFFTAG_FAXRECVPARAMS: + *va_arg(ap, uint32*) = codec->recvparams; + break; + + case TIFFTAG_FAXSUBADDRESS: + *va_arg(ap, char**) = codec->subaddress; + break; + + case TIFFTAG_FAXRECVTIME: + *va_arg(ap, uint32*) = codec->recvtime; + break; + + case TIFFTAG_FAXDCS: + *va_arg(ap, char**) = codec->faxdcs; + break; + + default: + return (*codec->vgetparent)(tif, tag, ap); + } + + return 1; +} + +static int JBIGVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JBIGState* codec = GetJBIGState(tif); + + switch (tag) + { + case TIFFTAG_FAXRECVPARAMS: + codec->recvparams = va_arg(ap, uint32); + break; + + case TIFFTAG_FAXSUBADDRESS: + _TIFFsetString(&codec->subaddress, va_arg(ap, char*)); + break; + + case TIFFTAG_FAXRECVTIME: + codec->recvtime = va_arg(ap, uint32); + break; + + case TIFFTAG_FAXDCS: + _TIFFsetString(&codec->faxdcs, va_arg(ap, char*)); + break; + + default: + return (*codec->vsetparent)(tif, tag, ap); + } + + TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +int TIFFInitJBIG(TIFF* tif, int scheme) +{ + JBIGState* codec = NULL; + + assert(scheme == COMPRESSION_JBIG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, jbigFieldInfo, + TIFFArrayCount(jbigFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitJBIG", + "Merging JBIG codec-specific tags failed"); + return 0; + } + + /* Allocate memory for the JBIGState structure.*/ + tif->tif_data = (tdata_t)_TIFFmalloc(sizeof(JBIGState)); + if (tif->tif_data == NULL) + { + TIFFError("TIFFInitJBIG", "Not enough memory for JBIGState"); + return 0; + } + _TIFFmemset(tif->tif_data, 0, sizeof(JBIGState)); + codec = GetJBIGState(tif); + + /* Initialize codec private fields */ + codec->recvparams = 0; + codec->subaddress = NULL; + codec->faxdcs = NULL; + codec->recvtime = 0; + + /* + * Override parent get/set field methods. + */ + codec->vgetparent = tif->tif_tagmethods.vgetfield; + codec->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vgetfield = JBIGVGetField; + tif->tif_tagmethods.vsetfield = JBIGVSetField; + tif->tif_tagmethods.printdir = JBIGPrintDir; + + /* + * These flags are set so the JBIG Codec can control when to reverse + * bits and when not to and to allow the jbig decoder and bit reverser + * to write to memory when necessary. + */ + tif->tif_flags |= TIFF_NOBITREV; + tif->tif_flags &= ~TIFF_MAPPED; + + /* Setup the function pointers for encode, decode, and cleanup. */ + tif->tif_setupdecode = JBIGSetupDecode; + tif->tif_decodestrip = JBIGDecode; + + tif->tif_setupencode = JBIGSetupEncode; + tif->tif_encodestrip = JBIGEncode; + + tif->tif_cleanup = JBIGCleanup; + + return 1; +} + +#endif /* JBIG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_jpeg.c b/thirdparty/libtiff/tif_jpeg.c new file mode 100644 index 00000000..a967827e --- /dev/null +++ b/thirdparty/libtiff/tif_jpeg.c @@ -0,0 +1,2065 @@ +/* $Id: tif_jpeg.c,v 1.50.2.9 2010-06-14 02:47:16 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1994-1997 Sam Leffler + * Copyright (c) 1994-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +#include "tiffiop.h" +#ifdef JPEG_SUPPORT + +/* + * TIFF Library + * + * JPEG Compression support per TIFF Technical Note #2 + * (*not* per the original TIFF 6.0 spec). + * + * This file is simply an interface to the libjpeg library written by + * the Independent JPEG Group. You need release 5 or later of the IJG + * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/. + * + * Contributed by Tom Lane . + */ +#include + +int TIFFFillStrip(TIFF*, tstrip_t); +int TIFFFillTile(TIFF*, ttile_t); + +/* We undefine FAR to avoid conflict with JPEG definition */ + +#ifdef FAR +#undef FAR +#endif + +/* + Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is + not defined. Unfortunately, the MinGW and Borland compilers include + a typedef for INT32, which causes a conflict. MSVC does not include + a conficting typedef given the headers which are included. +*/ +#if defined(__BORLANDC__) || defined(__MINGW32__) +# define XMD_H 1 +#endif + +/* + The windows RPCNDR.H file defines boolean, but defines it with the + unsigned char size. You should compile JPEG library using appropriate + definitions in jconfig.h header, but many users compile library in wrong + way. That causes errors of the following type: + + "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432, + caller expects 464" + + For such users we wil fix the problem here. See install.doc file from + the JPEG library distribution for details. +*/ + +/* Define "boolean" as unsigned char, not int, per Windows custom. */ +#if defined(WIN32) && !defined(__MINGW32__) +# ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; +# endif +# define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#include "jpeglib.h" +#include "jerror.h" + +/* + * We are using width_in_blocks which is supposed to be private to + * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has + * renamed this member to width_in_data_units. Since the header has + * also renamed a define, use that unique define name in order to + * detect the problem header and adjust to suit. + */ +#if defined(D_MAX_DATA_UNITS_IN_MCU) +#define width_in_blocks width_in_data_units +#endif + +/* + * On some machines it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. + */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf + +typedef struct jpeg_destination_mgr jpeg_destination_mgr; +typedef struct jpeg_source_mgr jpeg_source_mgr; +typedef struct jpeg_error_mgr jpeg_error_mgr; + +/* + * State block for each open TIFF file using + * libjpeg to do JPEG compression/decompression. + * + * libjpeg's visible state is either a jpeg_compress_struct + * or jpeg_decompress_struct depending on which way we + * are going. comm can be used to refer to the fields + * which are common to both. + * + * NB: cinfo is required to be the first member of JPEGState, + * so we can safely cast JPEGState* -> jpeg_xxx_struct* + * and vice versa! + */ +typedef struct { + union { + struct jpeg_compress_struct c; + struct jpeg_decompress_struct d; + struct jpeg_common_struct comm; + } cinfo; /* NB: must be first */ + int cinfo_initialized; + + jpeg_error_mgr err; /* libjpeg error manager */ + JMP_BUF exit_jmpbuf; /* for catching libjpeg failures */ + /* + * The following two members could be a union, but + * they're small enough that it's not worth the effort. + */ + jpeg_destination_mgr dest; /* data dest for compression */ + jpeg_source_mgr src; /* data source for decompression */ + /* private state */ + TIFF* tif; /* back link needed by some code */ + uint16 photometric; /* copy of PhotometricInterpretation */ + uint16 h_sampling; /* luminance sampling factors */ + uint16 v_sampling; + tsize_t bytesperline; /* decompressed bytes per scanline */ + /* pointers to intermediate buffers when processing downsampled data */ + JSAMPARRAY ds_buffer[MAX_COMPONENTS]; + int scancount; /* number of "scanlines" accumulated */ + int samplesperclump; + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFStripMethod defsparent; /* super-class method */ + TIFFTileMethod deftparent; /* super-class method */ + /* pseudo-tag fields */ + void* jpegtables; /* JPEGTables tag value, or NULL */ + uint32 jpegtables_length; /* number of bytes in same */ + int jpegquality; /* Compression quality level */ + int jpegcolormode; /* Auto RGB<=>YCbCr convert? */ + int jpegtablesmode; /* What to put in JPEGTables */ + + int ycbcrsampling_fetched; + uint32 recvparams; /* encoded Class 2 session params */ + char* subaddress; /* subaddress string */ + uint32 recvtime; /* time spent receiving (secs) */ + char* faxdcs; /* encoded fax parameters (DCS, Table 2/T.30) */ +} JPEGState; + +#define JState(tif) ((JPEGState*)(tif)->tif_data) + +static int JPEGDecode(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGDecodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGEncodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGInitializeLibJPEG( TIFF * tif, + int force_encode, int force_decode ); + +#define FIELD_JPEGTABLES (FIELD_CODEC+0) +#define FIELD_RECVPARAMS (FIELD_CODEC+1) +#define FIELD_SUBADDRESS (FIELD_CODEC+2) +#define FIELD_RECVTIME (FIELD_CODEC+3) +#define FIELD_FAXDCS (FIELD_CODEC+4) + +static const TIFFFieldInfo jpegFieldInfo[] = { + { TIFFTAG_JPEGTABLES, -3,-3, TIFF_UNDEFINED, FIELD_JPEGTABLES, + FALSE, TRUE, "JPEGTables" }, + { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO, + TRUE, FALSE, "" }, + { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "" }, + { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "" }, + /* Specific for JPEG in faxes */ + { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, + TRUE, FALSE, "FaxRecvParams" }, + { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS, + TRUE, FALSE, "FaxSubAddress" }, + { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, + TRUE, FALSE, "FaxRecvTime" }, + { TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, FIELD_FAXDCS, + TRUE, FALSE, "FaxDcs" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +/* + * libjpeg interface layer. + * + * We use setjmp/longjmp to return control to libtiff + * when a fatal error is encountered within the JPEG + * library. We also direct libjpeg error and warning + * messages through the appropriate libtiff handlers. + */ + +/* + * Error handling routines (these replace corresponding + * IJG routines from jerror.c). These are used for both + * compression and decompression. + */ +static void +TIFFjpeg_error_exit(j_common_ptr cinfo) +{ + JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFErrorExt(sp->tif->tif_clientdata, "JPEGLib", "%s", buffer); /* display the error message */ + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ +} + +/* + * This routine is invoked only for warning messages, + * since error_exit does its own thing and trace_level + * is never set > 0. + */ +static void +TIFFjpeg_output_message(j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFWarningExt(((JPEGState *) cinfo)->tif->tif_clientdata, "JPEGLib", "%s", buffer); +} + +/* + * Interface routines. This layer of routines exists + * primarily to limit side-effects from using setjmp. + * Also, normal/error returns are converted into return + * values per libtiff practice. + */ +#define CALLJPEG(sp, fail, op) (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op)) +#define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1)) + +static int +TIFFjpeg_create_compress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.c.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_create_decompress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.d.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_set_defaults(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); +} + +static int +TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace) +{ + return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); +} + +static int +TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline) +{ + return CALLVJPEG(sp, + jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); +} + +static int +TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress) +{ + return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); +} + +static int +TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables) +{ + return CALLVJPEG(sp, + jpeg_start_compress(&sp->cinfo.c, write_all_tables)); +} + +static int +TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, + scanlines, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c, + data, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_finish_compress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_write_tables(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); +} + +static int +TIFFjpeg_read_header(JPEGState* sp, boolean require_image) +{ + return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); +} + +static int +TIFFjpeg_start_decompress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, + scanlines, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d, + data, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_finish_decompress(JPEGState* sp) +{ + return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_abort(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm)); +} + +static int +TIFFjpeg_destroy(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm)); +} + +static JSAMPARRAY +TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +{ + return CALLJPEG(sp, (JSAMPARRAY) NULL, + (*sp->cinfo.comm.mem->alloc_sarray) + (&sp->cinfo.comm, pool_id, samplesperrow, numrows)); +} + +/* + * JPEG library destination data manager. + * These routines direct compressed data from libjpeg into the + * libtiff output buffer. + */ + +static void +std_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; +} + +static boolean +std_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + /* the entire buffer has been filled */ + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; + + return (TRUE); +} + +static void +std_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + tif->tif_rawcp = (tidata_t) sp->dest.next_output_byte; + tif->tif_rawcc = + tif->tif_rawdatasize - (tsize_t) sp->dest.free_in_buffer; + /* NB: libtiff does the final buffer flush */ +} + +static void +TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = std_init_destination; + sp->dest.empty_output_buffer = std_empty_output_buffer; + sp->dest.term_destination = std_term_destination; +} + +/* + * Alternate destination manager for outputting to JPEGTables field. + */ + +static void +tables_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* while building, jpegtables_length is allocated buffer size */ + sp->dest.next_output_byte = (JOCTET*) sp->jpegtables; + sp->dest.free_in_buffer = (size_t) sp->jpegtables_length; +} + +static boolean +tables_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + void* newbuf; + + /* the entire buffer has been filled; enlarge it by 1000 bytes */ + newbuf = _TIFFrealloc((tdata_t) sp->jpegtables, + (tsize_t) (sp->jpegtables_length + 1000)); + if (newbuf == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100); + sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length; + sp->dest.free_in_buffer = (size_t) 1000; + sp->jpegtables = newbuf; + sp->jpegtables_length += 1000; + return (TRUE); +} + +static void +tables_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* set tables length to number of bytes actually emitted */ + sp->jpegtables_length -= sp->dest.free_in_buffer; +} + +static int +TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + /* + * Allocate a working buffer for building tables. + * Initial size is 1000 bytes, which is usually adequate. + */ + if (sp->jpegtables) + _TIFFfree(sp->jpegtables); + sp->jpegtables_length = 1000; + sp->jpegtables = (void*) _TIFFmalloc((tsize_t) sp->jpegtables_length); + if (sp->jpegtables == NULL) { + sp->jpegtables_length = 0; + TIFFErrorExt(sp->tif->tif_clientdata, "TIFFjpeg_tables_dest", "No space for JPEGTables"); + return (0); + } + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = tables_init_destination; + sp->dest.empty_output_buffer = tables_empty_output_buffer; + sp->dest.term_destination = tables_term_destination; + return (1); +} + +/* + * JPEG library source data manager. + * These routines supply compressed data to libjpeg. + */ + +static void +std_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; +} + +static boolean +std_fill_input_buffer(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState* ) cinfo; + static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI }; + + /* + * Should never get here since entire strip/tile is + * read into memory before the decompressor is called, + * and thus was supplied by init_source. + */ + WARNMS(cinfo, JWRN_JPEG_EOF); + /* insert a fake EOI marker */ + sp->src.next_input_byte = dummy_EOI; + sp->src.bytes_in_buffer = 2; + return (TRUE); +} + +static void +std_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + JPEGState* sp = (JPEGState*) cinfo; + + if (num_bytes > 0) { + if (num_bytes > (long) sp->src.bytes_in_buffer) { + /* oops, buffer overrun */ + (void) std_fill_input_buffer(cinfo); + } else { + sp->src.next_input_byte += (size_t) num_bytes; + sp->src.bytes_in_buffer -= (size_t) num_bytes; + } + } +} + +static void +std_term_source(j_decompress_ptr cinfo) +{ + /* No work necessary here */ + /* Or must we update tif->tif_rawcp, tif->tif_rawcc ??? */ + /* (if so, need empty tables_term_source!) */ + (void) cinfo; +} + +static void +TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.d.src = &sp->src; + sp->src.init_source = std_init_source; + sp->src.fill_input_buffer = std_fill_input_buffer; + sp->src.skip_input_data = std_skip_input_data; + sp->src.resync_to_restart = jpeg_resync_to_restart; + sp->src.term_source = std_term_source; + sp->src.bytes_in_buffer = 0; /* for safety */ + sp->src.next_input_byte = NULL; +} + +/* + * Alternate source manager for reading from JPEGTables. + * We can share all the code except for the init routine. + */ + +static void +tables_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + sp->src.next_input_byte = (const JOCTET*) sp->jpegtables; + sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length; +} + +static void +TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) +{ + TIFFjpeg_data_src(sp, tif); + sp->src.init_source = tables_init_source; +} + +/* + * Allocate downsampled-data buffers needed for downsampled I/O. + * We use values computed in jpeg_start_compress or jpeg_start_decompress. + * We use libjpeg's allocator so that buffers will be released automatically + * when done with strip/tile. + * This is also a handy place to compute samplesperclump, bytesperline. + */ +static int +alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info, + int num_components) +{ + JPEGState* sp = JState(tif); + int ci; + jpeg_component_info* compptr; + JSAMPARRAY buf; + int samples_per_clump = 0; + + for (ci = 0, compptr = comp_info; ci < num_components; + ci++, compptr++) { + samples_per_clump += compptr->h_samp_factor * + compptr->v_samp_factor; + buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor*DCTSIZE)); + if (buf == NULL) + return (0); + sp->ds_buffer[ci] = buf; + } + sp->samplesperclump = samples_per_clump; + return (1); +} + + +/* + * JPEG Decoding. + */ + +static int +JPEGSetupDecode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + JPEGInitializeLibJPEG( tif, 0, 1 ); + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + + /* Read JPEGTables if it is present */ + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { + TIFFjpeg_tables_src(sp, tif); + if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) { + TIFFErrorExt(tif->tif_clientdata, "JPEGSetupDecode", "Bogus JPEGTables field"); + return (0); + } + } + + /* Grab parameters that are same for all strips/tiles */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + break; + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Set up for reading normal data */ + TIFFjpeg_data_src(sp, tif); + tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ + return (1); +} + +/* + * Set up for decoding a strip or tile. + */ +static int +JPEGPreDecode(TIFF* tif, tsample_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreDecode"; + uint32 segment_width, segment_height; + int downsampled_output; + int ci; + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + /* + * Reset decoder state from any previous strip/tile, + * in case application didn't read the whole strip. + */ + if (!TIFFjpeg_abort(sp)) + return (0); + /* + * Read the header for this strip/tile. + */ + if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK) + return (0); + /* + * Check image parameters and set decompression parameters. + */ + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFOldScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* + * For PC 2, scale down the expected strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany(segment_width, sp->h_sampling); + segment_height = TIFFhowmany(segment_height, sp->v_sampling); + } + if (sp->cinfo.d.image_width < segment_width || + sp->cinfo.d.image_height < segment_height) { + TIFFWarningExt(tif->tif_clientdata, module, + "Improper JPEG strip/tile size, " + "expected %dx%d, got %dx%d", + segment_width, segment_height, + sp->cinfo.d.image_width, + sp->cinfo.d.image_height); + } + if (sp->cinfo.d.image_width > segment_width || + sp->cinfo.d.image_height > segment_height) { + /* + * This case could be dangerous, if the strip or tile size has + * been reported as less than the amount of data jpeg will + * return, some potential security issues arise. Catch this + * case and error out. + */ + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG strip/tile size exceeds expected dimensions," + " expected %dx%d, got %dx%d", + segment_width, segment_height, + sp->cinfo.d.image_width, sp->cinfo.d.image_height); + return (0); + } + if (sp->cinfo.d.num_components != + (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1)) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG component count"); + return (0); + } +#ifdef JPEG_LIB_MK1 + if (12 != td->td_bitspersample && 8 != td->td_bitspersample) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision"); + return (0); + } + sp->cinfo.d.data_precision = td->td_bitspersample; + sp->cinfo.d.bits_in_jsample = td->td_bitspersample; +#else + if (sp->cinfo.d.data_precision != td->td_bitspersample) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision"); + return (0); + } +#endif + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + /* Component 0 should have expected sampling factors */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling || + sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) { + TIFFWarningExt(tif->tif_clientdata, module, + "Improper JPEG sampling factors %d,%d\n" + "Apparently should be %d,%d.", + sp->cinfo.d.comp_info[0].h_samp_factor, + sp->cinfo.d.comp_info[0].v_samp_factor, + sp->h_sampling, sp->v_sampling); + + /* + * There are potential security issues here + * for decoders that have already allocated + * buffers based on the expected sampling + * factors. Lets check the sampling factors + * dont exceed what we were expecting. + */ + if (sp->cinfo.d.comp_info[0].h_samp_factor + > sp->h_sampling + || sp->cinfo.d.comp_info[0].v_samp_factor + > sp->v_sampling) { + TIFFErrorExt(tif->tif_clientdata, + module, + "Cannot honour JPEG sampling factors" + " that exceed those specified."); + return (0); + } + + /* + * XXX: Files written by the Intergraph software + * has different sampling factors stored in the + * TIFF tags and in the JPEG structures. We will + * try to deduce Intergraph files by the presense + * of the tag 33918. + */ + if (!_TIFFFindFieldInfo(tif, 33918, TIFF_ANY)) { + TIFFWarningExt(tif->tif_clientdata, module, + "Decompressor will try reading with " + "sampling %d,%d.", + sp->cinfo.d.comp_info[0].h_samp_factor, + sp->cinfo.d.comp_info[0].v_samp_factor); + + sp->h_sampling = (uint16) + sp->cinfo.d.comp_info[0].h_samp_factor; + sp->v_sampling = (uint16) + sp->cinfo.d.comp_info[0].v_samp_factor; + } + } + /* Rest should have sampling factors 1,1 */ + for (ci = 1; ci < sp->cinfo.d.num_components; ci++) { + if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 || + sp->cinfo.d.comp_info[ci].v_samp_factor != 1) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors"); + return (0); + } + } + } else { + /* PC 2's single component should have sampling factors 1,1 */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 || + sp->cinfo.d.comp_info[0].v_samp_factor != 1) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors"); + return (0); + } + } + downsampled_output = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + sp->photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + /* Convert YCbCr to RGB */ + sp->cinfo.d.jpeg_color_space = JCS_YCbCr; + sp->cinfo.d.out_color_space = JCS_RGB; + } else { + /* Suppress colorspace handling */ + sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN; + sp->cinfo.d.out_color_space = JCS_UNKNOWN; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + (sp->h_sampling != 1 || sp->v_sampling != 1)) + downsampled_output = TRUE; + /* XXX what about up-sampling? */ + } + if (downsampled_output) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.d.raw_data_out = TRUE; + tif->tif_decoderow = JPEGDecodeRaw; + tif->tif_decodestrip = JPEGDecodeRaw; + tif->tif_decodetile = JPEGDecodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.d.raw_data_out = FALSE; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + } + /* Start JPEG decompressor */ + if (!TIFFjpeg_start_decompress(sp)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_output) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info, + sp->cinfo.d.num_components)) + return (0); + sp->scancount = DCTSIZE; /* mark buffer empty */ + } + return (1); +} + +/* + * Decode a chunk of pixels. + * "Standard" case: returned data is not downsampled. + */ +/*ARGSUSED*/ static int +JPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + (void) s; + + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read"); + + if( nrows > (int) sp->cinfo.d.image_height ) + nrows = sp->cinfo.d.image_height; + + /* data is expected to be read in multiples of a scanline */ + if (nrows) + { + JSAMPROW line_work_buf = NULL; + + /* + ** For 6B, only use temporary buffer for 12 bit imagery. + ** For Mk1 always use it. + */ +#if !defined(JPEG_LIB_MK1) + if( sp->cinfo.d.data_precision == 12 ) +#endif + { + line_work_buf = (JSAMPROW) + _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width + * sp->cinfo.d.num_components ); + } + + do { + if( line_work_buf != NULL ) + { + /* + ** In the MK1 case, we aways read into a 16bit buffer, and then + ** pack down to 12bit or 8bit. In 6B case we only read into 16 + ** bit buffer for 12bit data, which we need to repack. + */ + if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) + return (0); + + if( sp->cinfo.d.data_precision == 12 ) + { + int value_pairs = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; + + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = + ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = line_work_buf + iPair * 2; + + out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; + out_ptr[1] = ((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8); + out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); + } + } + else if( sp->cinfo.d.data_precision == 8 ) + { + int value_count = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components); + int iValue; + + for( iValue = 0; iValue < value_count; iValue++ ) + { + ((unsigned char *) buf)[iValue] = + line_work_buf[iValue] & 0xff; + } + } + } + else + { + /* + ** In the libjpeg6b 8bit case. We read directly into the + ** TIFF buffer. + */ + JSAMPROW bufptr = (JSAMPROW)buf; + + if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) + return (0); + } + + ++tif->tif_row; + buf += sp->bytesperline; + cc -= sp->bytesperline; + } while (--nrows > 0); + + if( line_work_buf != NULL ) + _TIFFfree( line_work_buf ); + } + + /* Close down the decompressor if we've finished the strip or tile. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} + +/* + * Decode a chunk of pixels. + * Returned data is downsampled per sampling factors. + */ +/*ARGSUSED*/ static int +JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + (void) s; + + /* data is expected to be read in multiples of a scanline */ + if ( (nrows = sp->cinfo.d.image_height) ) { + /* Cb,Cr both have sampling factors 1, so this is correct */ + JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width; + int samples_per_clump = sp->samplesperclump; + +#ifdef JPEG_LIB_MK1 + unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) * + sp->cinfo.d.output_width * + sp->cinfo.d.num_components); +#endif + + do { + jpeg_component_info *compptr; + int ci, clumpoffset; + + /* Reload downsampled-data buffer if needed */ + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + /* + * Fastest way to unseparate data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.d.comp_info; + ci < sp->cinfo.d.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int ypos; + + for (ypos = 0; ypos < vsamp; ypos++) { + JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; +#ifdef JPEG_LIB_MK1 + JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset; +#else + JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset; +#endif + JDIMENSION nclump; + + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + outptr[0] = *inptr++; + outptr += samples_per_clump; + } + } else { + int xpos; + + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + outptr[xpos] = *inptr++; + outptr += samples_per_clump; + } + } + clumpoffset += hsamp; + } + } + +#ifdef JPEG_LIB_MK1 + { + if (sp->cinfo.d.data_precision == 8) + { + int i=0; + int len = sp->cinfo.d.output_width * sp->cinfo.d.num_components; + for (i=0; icinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = tmpbuf + iPair * 2; + out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; + out_ptr[1] = ((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8); + out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); + } + } + } +#endif + + sp->scancount ++; + tif->tif_row += sp->v_sampling; + /* increment/decrement of buf and cc is still incorrect, but should not matter + * TODO: resolve this */ + buf += sp->bytesperline; + cc -= sp->bytesperline; + nrows -= sp->v_sampling; + } while (nrows > 0); + +#ifdef JPEG_LIB_MK1 + _TIFFfree(tmpbuf); +#endif + + } + + /* Close down the decompressor if done. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} + + +/* + * JPEG Encoding. + */ + +static void +unsuppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = FALSE; +} + +static void +unsuppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; +} + +static int +prepare_JPEGTables(TIFF* tif) +{ + JPEGState* sp = JState(tif); + + JPEGInitializeLibJPEG( tif, 0, 0 ); + + /* Initialize quant tables for current quality setting */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + /* Mark only the tables we want for output */ + /* NB: chrominance tables are currently used only with YCbCr */ + if (!TIFFjpeg_suppress_tables(sp, TRUE)) + return (0); + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + unsuppress_quant_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) { + unsuppress_huff_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_huff_table(sp, 1); + } + /* Direct libjpeg output into jpegtables */ + if (!TIFFjpeg_tables_dest(sp, tif)) + return (0); + /* Emit tables-only datastream */ + if (!TIFFjpeg_write_tables(sp)) + return (0); + + return (1); +} + +static int +JPEGSetupEncode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGSetupEncode"; + + JPEGInitializeLibJPEG( tif, 1, 0 ); + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + + /* + * Initialize all JPEG parameters to default values. + * Note that jpeg_set_defaults needs legal values for + * in_color_space and input_components. + */ + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + sp->cinfo.c.input_components = 1; + if (!TIFFjpeg_set_defaults(sp)) + return (0); + /* Set per-file parameters */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + /* + * A ReferenceBlackWhite field *must* be present since the + * default value is inappropriate for YCbCr. Fill in the + * proper value if application didn't set it. + */ + { + float *ref; + if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE, + &ref)) { + float refbw[6]; + long top = 1L << td->td_bitspersample; + refbw[0] = 0; + refbw[1] = (float)(top-1L); + refbw[2] = (float)(top>>1); + refbw[3] = refbw[1]; + refbw[4] = refbw[2]; + refbw[5] = refbw[1]; + TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, + refbw); + } + } + break; + case PHOTOMETRIC_PALETTE: /* disallowed by Tech Note */ + case PHOTOMETRIC_MASK: + TIFFErrorExt(tif->tif_clientdata, module, + "PhotometricInterpretation %d not allowed for JPEG", + (int) sp->photometric); + return (0); + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Verify miscellaneous parameters */ + + /* + * This would need work if libtiff ever supports different + * depths for different components, or if libjpeg ever supports + * run-time selection of depth. Neither is imminent. + */ +#ifdef JPEG_LIB_MK1 + /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */ + if (td->td_bitspersample != 8 && td->td_bitspersample != 12) +#else + if (td->td_bitspersample != BITS_IN_JSAMPLE ) +#endif + { + TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %d not allowed for JPEG", + (int) td->td_bitspersample); + return (0); + } + sp->cinfo.c.data_precision = td->td_bitspersample; +#ifdef JPEG_LIB_MK1 + sp->cinfo.c.bits_in_jsample = td->td_bitspersample; +#endif + if (isTiled(tif)) { + if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG tile height must be multiple of %d", + sp->v_sampling * DCTSIZE); + return (0); + } + if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG tile width must be multiple of %d", + sp->h_sampling * DCTSIZE); + return (0); + } + } else { + if (td->td_rowsperstrip < td->td_imagelength && + (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "RowsPerStrip must be multiple of %d for JPEG", + sp->v_sampling * DCTSIZE); + return (0); + } + } + + /* Create a JPEGTables field if appropriate */ + if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) { + if( sp->jpegtables == NULL + || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 ) + { + if (!prepare_JPEGTables(tif)) + return (0); + /* Mark the field present */ + /* Can't use TIFFSetField since BEENWRITING is already set! */ + tif->tif_flags |= TIFF_DIRTYDIRECT; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + } + } else { + /* We do not support application-supplied JPEGTables, */ + /* so mark the field not present */ + TIFFClrFieldBit(tif, FIELD_JPEGTABLES); + } + + /* Direct libjpeg output to libtiff's output buffer */ + TIFFjpeg_data_dest(sp, tif); + + return (1); +} + +/* + * Set encoding state at the start of a strip or tile. + */ +static int +JPEGPreEncode(TIFF* tif, tsample_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreEncode"; + uint32 segment_width, segment_height; + int downsampled_input; + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + /* + * Set encoding parameters for this strip/tile. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFOldScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* for PC 2, scale down the strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany(segment_width, sp->h_sampling); + segment_height = TIFFhowmany(segment_height, sp->v_sampling); + } + if (segment_width > 65535 || segment_height > 65535) { + TIFFErrorExt(tif->tif_clientdata, module, "Strip/tile too large for JPEG"); + return (0); + } + sp->cinfo.c.image_width = segment_width; + sp->cinfo.c.image_height = segment_height; + downsampled_input = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + sp->cinfo.c.input_components = td->td_samplesperpixel; + if (sp->photometric == PHOTOMETRIC_YCBCR) { + if (sp->jpegcolormode == JPEGCOLORMODE_RGB) { + sp->cinfo.c.in_color_space = JCS_RGB; + } else { + sp->cinfo.c.in_color_space = JCS_YCbCr; + if (sp->h_sampling != 1 || sp->v_sampling != 1) + downsampled_input = TRUE; + } + if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr)) + return (0); + /* + * Set Y sampling factors; + * we assume jpeg_set_colorspace() set the rest to 1 + */ + sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; + sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; + } else { + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + /* jpeg_set_colorspace set all sampling factors to 1 */ + } + } else { + sp->cinfo.c.input_components = 1; + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + sp->cinfo.c.comp_info[0].component_id = s; + /* jpeg_set_colorspace() set sampling factors to 1 */ + if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) { + sp->cinfo.c.comp_info[0].quant_tbl_no = 1; + sp->cinfo.c.comp_info[0].dc_tbl_no = 1; + sp->cinfo.c.comp_info[0].ac_tbl_no = 1; + } + } + /* ensure libjpeg won't write any extraneous markers */ + sp->cinfo.c.write_JFIF_header = FALSE; + sp->cinfo.c.write_Adobe_marker = FALSE; + /* set up table handling correctly */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { + unsuppress_quant_table(sp, 0); + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) + sp->cinfo.c.optimize_coding = FALSE; + else + sp->cinfo.c.optimize_coding = TRUE; + if (downsampled_input) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.c.raw_data_in = TRUE; + tif->tif_encoderow = JPEGEncodeRaw; + tif->tif_encodestrip = JPEGEncodeRaw; + tif->tif_encodetile = JPEGEncodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.c.raw_data_in = FALSE; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + } + /* Start JPEG compressor */ + if (!TIFFjpeg_start_compress(sp, FALSE)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_input) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info, + sp->cinfo.c.num_components)) + return (0); + } + sp->scancount = 0; + + return (1); +} + +/* + * Encode a chunk of pixels. + * "Standard" case: incoming data is not downsampled. + */ +static int +JPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + JSAMPROW bufptr[1]; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded"); + + /* The last strip will be limited to image size */ + if( !isTiled(tif) && tif->tif_row+nrows > tif->tif_dir.td_imagelength ) + nrows = tif->tif_dir.td_imagelength - tif->tif_row; + + while (nrows-- > 0) { + bufptr[0] = (JSAMPROW) buf; + if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + return (1); +} + +/* + * Encode a chunk of pixels. + * Incoming data is expected to be downsampled per sampling factors. + */ +static int +JPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + tsize_t bytesperclumpline; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a clumpline */ + /* a clumpline is equivalent to v_sampling desubsampled scanlines */ + /* TODO: the following calculation of bytesperclumpline, should substitute calculation of sp->bytesperline, except that it is per v_sampling lines */ + bytesperclumpline = (((sp->cinfo.c.image_width+sp->h_sampling-1)/sp->h_sampling) + *(sp->h_sampling*sp->v_sampling+2)*sp->cinfo.c.data_precision+7) + /8; + + nrows = ( cc / bytesperclumpline ) * sp->v_sampling; + if (cc % bytesperclumpline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width; + + while (nrows > 0) { + /* + * Fastest way to separate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int padding = (int) (compptr->width_in_blocks * DCTSIZE - + clumps_per_line * hsamp); + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = ((JSAMPLE*) buf) + clumpoffset; + outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + *outptr++ = inptr[0]; + inptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + *outptr++ = inptr[xpos]; + inptr += samples_per_clump; + } + } + /* pad each scanline as needed */ + for (xpos = 0; xpos < padding; xpos++) { + *outptr = outptr[-1]; + outptr++; + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + tif->tif_row += sp->v_sampling; + buf += sp->bytesperline; + nrows -= sp->v_sampling; + } + return (1); +} + +/* + * Finish up at the end of a strip or tile. + */ +static int +JPEGPostEncode(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + if (sp->scancount > 0) { + /* + * Need to emit a partial bufferload of downsampled data. + * Pad the data vertically. + */ + int ci, ypos, n; + jpeg_component_info* compptr; + + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int vsamp = compptr->v_samp_factor; + tsize_t row_width = compptr->width_in_blocks * DCTSIZE + * sizeof(JSAMPLE); + for (ypos = sp->scancount * vsamp; + ypos < DCTSIZE * vsamp; ypos++) { + _TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos], + (tdata_t)sp->ds_buffer[ci][ypos-1], + row_width); + + } + } + n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + } + + return (TIFFjpeg_finish_compress(JState(tif))); +} + +static void +JPEGCleanup(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + + if( sp->cinfo_initialized ) + TIFFjpeg_destroy(sp); /* release libjpeg resources */ + if (sp->jpegtables) /* tag value */ + _TIFFfree(sp->jpegtables); + _TIFFfree(tif->tif_data); /* release local state */ + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static void +JPEGResetUpsampled( TIFF* tif ) +{ + JPEGState* sp = JState(tif); + TIFFDirectory* td = &tif->tif_dir; + + /* + * Mark whether returned data is up-sampled or not so TIFFStripSize + * and TIFFTileSize return values that reflect the true amount of + * data. + */ + tif->tif_flags &= ~TIFF_UPSAMPLED; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + tif->tif_flags |= TIFF_UPSAMPLED; + } else { +#ifdef notdef + if (td->td_ycbcrsubsampling[0] != 1 || + td->td_ycbcrsubsampling[1] != 1) + ; /* XXX what about up-sampling? */ +#endif + } + } + + /* + * Must recalculate cached tile size in case sampling state changed. + * Should we really be doing this now if image size isn't set? + */ + if( tif->tif_tilesize > 0 ) + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1; + + if(tif->tif_scanlinesize > 0 ) + tif->tif_scanlinesize = TIFFScanlineSize(tif); +} + +static int +JPEGVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + const TIFFFieldInfo* fip; + uint32 v32; + + assert(sp != NULL); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + v32 = va_arg(ap, uint32); + if (v32 == 0) { + /* XXX */ + return (0); + } + _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), + (long) v32); + sp->jpegtables_length = v32; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + break; + case TIFFTAG_JPEGQUALITY: + sp->jpegquality = va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGCOLORMODE: + sp->jpegcolormode = va_arg(ap, int); + JPEGResetUpsampled( tif ); + return (1); /* pseudo tag */ + case TIFFTAG_PHOTOMETRIC: + { + int ret_value = (*sp->vsetparent)(tif, tag, ap); + JPEGResetUpsampled( tif ); + return ret_value; + } + case TIFFTAG_JPEGTABLESMODE: + sp->jpegtablesmode = va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_YCBCRSUBSAMPLING: + /* mark the fact that we have a real ycbcrsubsampling! */ + sp->ycbcrsampling_fetched = 1; + /* should we be recomputing upsampling info here? */ + return (*sp->vsetparent)(tif, tag, ap); + case TIFFTAG_FAXRECVPARAMS: + sp->recvparams = va_arg(ap, uint32); + break; + case TIFFTAG_FAXSUBADDRESS: + _TIFFsetString(&sp->subaddress, va_arg(ap, char*)); + break; + case TIFFTAG_FAXRECVTIME: + sp->recvtime = va_arg(ap, uint32); + break; + case TIFFTAG_FAXDCS: + _TIFFsetString(&sp->faxdcs, va_arg(ap, char*)); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + + if ((fip = _TIFFFieldWithTag(tif, tag))) { + TIFFSetFieldBit(tif, fip->field_bit); + } else { + return (0); + } + + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +/* + * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in + * the TIFF tags, but still use non-default (2,2) values within the jpeg + * data stream itself. In order for TIFF applications to work properly + * - for instance to get the strip buffer size right - it is imperative + * that the subsampling be available before we start reading the image + * data normally. This function will attempt to load the first strip in + * order to get the sampling values from the jpeg data stream. Various + * hacks are various places are done to ensure this function gets called + * before the td_ycbcrsubsampling values are used from the directory structure, + * including calling TIFFGetField() for the YCBCRSUBSAMPLING field from + * TIFFStripSize(), and the printing code in tif_print.c. + * + * Note that JPEGPreDeocode() will produce a fairly loud warning when the + * discovered sampling does not match the default sampling (2,2) or whatever + * was actually in the tiff tags. + * + * Problems: + * o This code will cause one whole strip/tile of compressed data to be + * loaded just to get the tags right, even if the imagery is never read. + * It would be more efficient to just load a bit of the header, and + * initialize things from that. + * + * See the bug in bugzilla for details: + * + * http://bugzilla.remotesensing.org/show_bug.cgi?id=168 + * + * Frank Warmerdam, July 2002 + */ + +static void +JPEGFixupTestSubsampling( TIFF * tif ) +{ +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + JPEGInitializeLibJPEG( tif, 0, 0 ); + + /* + * Some JPEG-in-TIFF files don't provide the ycbcrsampling tags, + * and use a sampling schema other than the default 2,2. To handle + * this we actually have to scan the header of a strip or tile of + * jpeg data to get the sampling. + */ + if( !sp->cinfo.comm.is_decompressor + || sp->ycbcrsampling_fetched + || td->td_photometric != PHOTOMETRIC_YCBCR ) + return; + + sp->ycbcrsampling_fetched = 1; + if( TIFFIsTiled( tif ) ) + { + if( !TIFFFillTile( tif, 0 ) ) + return; + } + else + { + if( !TIFFFillStrip( tif, 0 ) ) + return; + } + + TIFFSetField( tif, TIFFTAG_YCBCRSUBSAMPLING, + (uint16) sp->h_sampling, (uint16) sp->v_sampling ); + + /* + ** We want to clear the loaded strip so the application has time + ** to set JPEGCOLORMODE or other behavior modifiers. This essentially + ** undoes the JPEGPreDecode triggers by TIFFFileStrip(). (#1936) + */ + tif->tif_curstrip = -1; + +#endif /* CHECK_JPEG_YCBCR_SUBSAMPLING */ +} + +static int +JPEGVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + + assert(sp != NULL); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + *va_arg(ap, uint32*) = sp->jpegtables_length; + *va_arg(ap, void**) = sp->jpegtables; + break; + case TIFFTAG_JPEGQUALITY: + *va_arg(ap, int*) = sp->jpegquality; + break; + case TIFFTAG_JPEGCOLORMODE: + *va_arg(ap, int*) = sp->jpegcolormode; + break; + case TIFFTAG_JPEGTABLESMODE: + *va_arg(ap, int*) = sp->jpegtablesmode; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + JPEGFixupTestSubsampling( tif ); + return (*sp->vgetparent)(tif, tag, ap); + case TIFFTAG_FAXRECVPARAMS: + *va_arg(ap, uint32*) = sp->recvparams; + break; + case TIFFTAG_FAXSUBADDRESS: + *va_arg(ap, char**) = sp->subaddress; + break; + case TIFFTAG_FAXRECVTIME: + *va_arg(ap, uint32*) = sp->recvtime; + break; + case TIFFTAG_FAXDCS: + *va_arg(ap, char**) = sp->faxdcs; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +JPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + JPEGState* sp = JState(tif); + + assert(sp != NULL); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) + fprintf(fd, " JPEG Tables: (%lu bytes)\n", + (unsigned long) sp->jpegtables_length); + if (TIFFFieldSet(tif,FIELD_RECVPARAMS)) + fprintf(fd, " Fax Receive Parameters: %08lx\n", + (unsigned long) sp->recvparams); + if (TIFFFieldSet(tif,FIELD_SUBADDRESS)) + fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress); + if (TIFFFieldSet(tif,FIELD_RECVTIME)) + fprintf(fd, " Fax Receive Time: %lu secs\n", + (unsigned long) sp->recvtime); + if (TIFFFieldSet(tif,FIELD_FAXDCS)) + fprintf(fd, " Fax DCS: %s\n", sp->faxdcs); +} + +static uint32 +JPEGDefaultStripSize(TIFF* tif, uint32 s) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + s = (*sp->defsparent)(tif, s); + if (s < td->td_imagelength) + s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE); + return (s); +} + +static void +JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + (*sp->deftparent)(tif, tw, th); + *tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); + *th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE); +} + +/* + * The JPEG library initialized used to be done in TIFFInitJPEG(), but + * now that we allow a TIFF file to be opened in update mode it is necessary + * to have some way of deciding whether compression or decompression is + * desired other than looking at tif->tif_mode. We accomplish this by + * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry. + * If so, we assume decompression is desired. + * + * This is tricky, because TIFFInitJPEG() is called while the directory is + * being read, and generally speaking the BYTECOUNTS tag won't have been read + * at that point. So we try to defer jpeg library initialization till we + * do have that tag ... basically any access that might require the compressor + * or decompressor that occurs after the reading of the directory. + * + * In an ideal world compressors or decompressors would be setup + * at the point where a single tile or strip was accessed (for read or write) + * so that stuff like update of missing tiles, or replacement of tiles could + * be done. However, we aren't trying to crack that nut just yet ... + * + * NFW, Feb 3rd, 2003. + */ + +static int JPEGInitializeLibJPEG( TIFF * tif, int force_encode, int force_decode ) +{ + JPEGState* sp = JState(tif); + uint32 *byte_counts = NULL; + int data_is_empty = TRUE; + int decompress; + + + if(sp->cinfo_initialized) + { + if( force_encode && sp->cinfo.comm.is_decompressor ) + TIFFjpeg_destroy( sp ); + else if( force_decode && !sp->cinfo.comm.is_decompressor ) + TIFFjpeg_destroy( sp ); + else + return 1; + + sp->cinfo_initialized = 0; + } + + /* + * Do we have tile data already? Make sure we initialize the + * the state in decompressor mode if we have tile data, even if we + * are not in read-only file access mode. + */ + if( TIFFIsTiled( tif ) + && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &byte_counts ) + && byte_counts != NULL ) + { + data_is_empty = byte_counts[0] == 0; + } + if( !TIFFIsTiled( tif ) + && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &byte_counts) + && byte_counts != NULL ) + { + data_is_empty = byte_counts[0] == 0; + } + + if( force_decode ) + decompress = 1; + else if( force_encode ) + decompress = 0; + else if( tif->tif_mode == O_RDONLY ) + decompress = 1; + else if( data_is_empty ) + decompress = 0; + else + decompress = 1; + + /* + * Initialize libjpeg. + */ + if ( decompress ) { + if (!TIFFjpeg_create_decompress(sp)) + return (0); + + } else { + if (!TIFFjpeg_create_compress(sp)) + return (0); + } + + sp->cinfo_initialized = TRUE; + + return 1; +} + +int +TIFFInitJPEG(TIFF* tif, int scheme) +{ + JPEGState* sp; + + assert(scheme == COMPRESSION_JPEG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", + "Merging JPEG codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (JPEGState)); + + if (tif->tif_data == NULL) { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", "No space for JPEG state block"); + return 0; + } + _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState)); + + sp = JState(tif); + sp->tif = tif; /* back link */ + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = JPEGPrintDir; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->jpegtables = NULL; + sp->jpegtables_length = 0; + sp->jpegquality = 75; /* Default IJG quality */ + sp->jpegcolormode = JPEGCOLORMODE_RAW; + sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; + + sp->recvparams = 0; + sp->subaddress = NULL; + sp->faxdcs = NULL; + + sp->ycbcrsampling_fetched = 0; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = JPEGSetupDecode; + tif->tif_predecode = JPEGPreDecode; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + tif->tif_setupencode = JPEGSetupEncode; + tif->tif_preencode = JPEGPreEncode; + tif->tif_postencode = JPEGPostEncode; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + tif->tif_cleanup = JPEGCleanup; + sp->defsparent = tif->tif_defstripsize; + tif->tif_defstripsize = JPEGDefaultStripSize; + sp->deftparent = tif->tif_deftilesize; + tif->tif_deftilesize = JPEGDefaultTileSize; + tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ + + sp->cinfo_initialized = FALSE; + + /* + ** Create a JPEGTables field if no directory has yet been created. + ** We do this just to ensure that sufficient space is reserved for + ** the JPEGTables field. It will be properly created the right + ** size later. + */ + if( tif->tif_diroff == 0 ) + { +#define SIZE_OF_JPEGTABLES 2000 +/* +The following line assumes incorrectly that all JPEG-in-TIFF files will have +a JPEGTABLES tag generated and causes null-filled JPEGTABLES tags to be written +when the JPEG data is placed with TIFFWriteRawStrip. The field bit should be +set, anyway, later when actual JPEGTABLES header is generated, so removing it +here hopefully is harmless. + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); +*/ + sp->jpegtables_length = SIZE_OF_JPEGTABLES; + sp->jpegtables = (void *) _TIFFmalloc(sp->jpegtables_length); + _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES); +#undef SIZE_OF_JPEGTABLES + } + + /* + * Mark the TIFFTAG_YCBCRSAMPLES as present even if it is not + * see: JPEGFixupTestSubsampling(). + */ + TIFFSetFieldBit( tif, FIELD_YCBCRSUBSAMPLING ); + + return 1; +} +#endif /* JPEG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_luv.c b/thirdparty/libtiff/tif_luv.c new file mode 100644 index 00000000..eb622b9b --- /dev/null +++ b/thirdparty/libtiff/tif_luv.c @@ -0,0 +1,1629 @@ +/* $Id: tif_luv.c,v 1.17.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1997 Greg Ward Larson + * Copyright (c) 1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any + * advertising or publicity relating to the software without the specific, + * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE + * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LOGLUV_SUPPORT + +/* + * TIFF Library. + * LogLuv compression support for high dynamic range images. + * + * Contributed by Greg Larson. + * + * LogLuv image support uses the TIFF library to store 16 or 10-bit + * log luminance values with 8 bits each of u and v or a 14-bit index. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit integer values. A 16-bit luminance is interpreted + * as a sign bit followed by a 15-bit integer that is converted + * to and from a linear magnitude using the transformation: + * + * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit + * + * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real + * + * The actual conversion to world luminance units in candelas per sq. meter + * requires an additional multiplier, which is stored in the TIFFTAG_STONITS. + * This value is usually set such that a reasonable exposure comes from + * clamping decoded luminances above 1 to 1 in the displayed image. + * + * The 16-bit values for u and v may be converted to real values by dividing + * each by 32768. (This allows for negative values, which aren't useful as + * far as we know, but are left in case of future improvements in human + * color vision.) + * + * Conversion from (u,v), which is actually the CIE (u',v') system for + * you color scientists, is accomplished by the following transformation: + * + * u = 4*x / (-2*x + 12*y + 3) + * v = 9*y / (-2*x + 12*y + 3) + * + * x = 9*u / (6*u - 16*v + 12) + * y = 4*v / (6*u - 16*v + 12) + * + * This process is greatly simplified by passing 32-bit IEEE floats + * for each of three CIE XYZ coordinates. The codec then takes care + * of conversion to and from LogLuv, though the application is still + * responsible for interpreting the TIFFTAG_STONITS calibration factor. + * + * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white + * point of (x,y)=(1/3,1/3). However, most color systems assume some other + * white point, such as D65, and an absolute color conversion to XYZ then + * to another color space with a different white point may introduce an + * unwanted color cast to the image. It is often desirable, therefore, to + * perform a white point conversion that maps the input white to [1 1 1] + * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT + * tag value. A decoder that demands absolute color calibration may use + * this white point tag to get back the original colors, but usually it + * will be ignored and the new white point will be used instead that + * matches the output color space. + * + * Pixel information is compressed into one of two basic encodings, depending + * on the setting of the compression tag, which is one of COMPRESSION_SGILOG + * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is + * stored as: + * + * 1 15 + * |-+---------------| + * + * COMPRESSION_SGILOG color data is stored as: + * + * 1 15 8 8 + * |-+---------------|--------+--------| + * S Le ue ve + * + * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as: + * + * 10 14 + * |----------|--------------| + * Le' Ce + * + * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is + * encoded as an index for optimal color resolution. The 10 log bits are + * defined by the following conversions: + * + * L = 2^((Le'+.5)/64 - 12) # real from 10-bit + * + * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real + * + * The 10 bits of the smaller format may be converted into the 15 bits of + * the larger format by multiplying by 4 and adding 13314. Obviously, + * a smaller range of magnitudes is covered (about 5 orders of magnitude + * instead of 38), and the lack of a sign bit means that negative luminances + * are not allowed. (Well, they aren't allowed in the real world, either, + * but they are useful for certain types of image processing.) + * + * The desired user format is controlled by the setting the internal + * pseudo tag TIFFTAG_SGILOGDATAFMT to one of: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values + * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v + * Raw data i/o is also possible using: + * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel + * In addition, the following decoding is provided for ease of display: + * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values + * + * For grayscale images, we provide the following data formats: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values + * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance + * SGILOGDATAFMT_8BIT = 8-bit gray monitor values + * + * Note that the COMPRESSION_SGILOG applies a simple run-length encoding + * scheme by separating the logL, u and v bytes for each row and applying + * a PackBits type of compression. Since the 24-bit encoding is not + * adaptive, the 32-bit color format takes less space in many cases. + * + * Further control is provided over the conversion from higher-resolution + * formats to final encoded values through the pseudo tag + * TIFFTAG_SGILOGENCODE: + * SGILOGENCODE_NODITHER = do not dither encoded values + * SGILOGENCODE_RANDITHER = apply random dithering during encoding + * + * The default value of this tag is SGILOGENCODE_NODITHER for + * COMPRESSION_SGILOG to maximize run-length encoding and + * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn + * quantization errors into noise. + */ + +#include +#include +#include + +/* + * State block for each open TIFF + * file using LogLuv compression/decompression. + */ +typedef struct logLuvState LogLuvState; + +struct logLuvState { + int user_datafmt; /* user data format */ + int encode_meth; /* encoding method */ + int pixel_size; /* bytes per pixel */ + + tidata_t* tbuf; /* translation buffer */ + int tbuflen; /* buffer length */ + void (*tfunc)(LogLuvState*, tidata_t, int); + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +}; + +#define DecoderState(tif) ((LogLuvState*) (tif)->tif_data) +#define EncoderState(tif) ((LogLuvState*) (tif)->tif_data) + +#define SGILOGDATAFMT_UNKNOWN -1 + +#define MINRUN 4 /* minimum run length */ + +/* + * Decode a string of 16-bit gray pixels. + */ +static int +LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + LogLuvState* sp = DecoderState(tif); + int shft, i, npixels; + unsigned char* bp; + int16* tp; + int16 b; + int cc, rc; + + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16*) op; + else { + assert(sp->tbuflen >= npixels); + tp = (int16*) sp->tbuf; + } + _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); + + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 2*8; (shft -= 8) >= 0; ) { + for (i = 0; i < npixels && cc > 0; ) + if (*bp >= 128) { /* run */ + rc = *bp++ + (2-128); + b = (int16)(*bp++ << shft); + cc -= 2; + while (rc-- && i < npixels) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc-- && i < npixels) + tp[i++] |= (int16)*bp++ << shft; + } + if (i != npixels) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LogL16Decode: Not enough data at row %d (short %d pixels)", + tif->tif_row, npixels - i); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a string of 24-bit pixels. + */ +static int +LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + LogLuvState* sp = DecoderState(tif); + int cc, i, npixels; + unsigned char* bp; + uint32* tp; + + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32 *)op; + else { + assert(sp->tbuflen >= npixels); + tp = (uint32 *) sp->tbuf; + } + /* copy to array of uint32 */ + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + for (i = 0; i < npixels && cc > 0; i++) { + tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2]; + bp += 3; + cc -= 3; + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + if (i != npixels) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LogLuvDecode24: Not enough data at row %d (short %d pixels)", + tif->tif_row, npixels - i); + return (0); + } + (*sp->tfunc)(sp, op, npixels); + return (1); +} + +/* + * Decode a string of 32-bit pixels. + */ +static int +LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + LogLuvState* sp; + int shft, i, npixels; + unsigned char* bp; + uint32* tp; + uint32 b; + int cc, rc; + + assert(s == 0); + sp = DecoderState(tif); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) op; + else { + assert(sp->tbuflen >= npixels); + tp = (uint32*) sp->tbuf; + } + _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); + + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 4*8; (shft -= 8) >= 0; ) { + for (i = 0; i < npixels && cc > 0; ) + if (*bp >= 128) { /* run */ + rc = *bp++ + (2-128); + b = (uint32)*bp++ << shft; + cc -= 2; + while (rc-- && i < npixels) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc-- && i < npixels) + tp[i++] |= (uint32)*bp++ << shft; + } + if (i != npixels) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LogLuvDecode32: Not enough data at row %d (short %d pixels)", + tif->tif_row, npixels - i); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a strip of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFScanlineSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Decode a tile of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFTileRowSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode a row of 16-bit pixels. + */ +static int +LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + LogLuvState* sp = EncoderState(tif); + int shft, i, j, npixels; + tidata_t op; + int16* tp; + int16 b; + int occ, rc=0, mask, beg; + + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16*) bp; + else { + tp = (int16*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 2*8; (shft -= 8) >= 0; ) + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = (int16) (tp[beg] & mask); + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = (int16) (tp[i] & mask);/*check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (tidataval_t)(128-2+j-i); + *op++ = (tidataval_t) (b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (tidataval_t) j; occ--; + while (j--) { + *op++ = (tidataval_t) (tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = (tidataval_t) (128-2+rc); + *op++ = (tidataval_t) (tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a row of 24-bit pixels. + */ +static int +LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + LogLuvState* sp = EncoderState(tif); + int i, npixels, occ; + tidata_t op; + uint32* tp; + + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) bp; + else { + tp = (uint32*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* write out encoded pixels */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (i = npixels; i--; ) { + if (occ < 3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (tidataval_t)(*tp >> 16); + *op++ = (tidataval_t)(*tp >> 8 & 0xff); + *op++ = (tidataval_t)(*tp++ & 0xff); + occ -= 3; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a row of 32-bit pixels. + */ +static int +LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + LogLuvState* sp = EncoderState(tif); + int shft, i, j, npixels; + tidata_t op; + uint32* tp; + uint32 b; + int occ, rc=0, mask, beg; + + assert(s == 0); + assert(sp != NULL); + + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) bp; + else { + tp = (uint32*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 4*8; (shft -= 8) >= 0; ) + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = tp[beg] & mask; + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = tp[i] & mask; /* check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (tidataval_t)(128-2+j-i); + *op++ = (tidataval_t)(b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (tidataval_t) j; occ--; + while (j--) { + *op++ = (tidataval_t)(tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = (tidataval_t) (128-2+rc); + *op++ = (tidataval_t)(tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a strip of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFScanlineSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode a tile of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFTileRowSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode/Decode functions for converting to and from user formats. + */ + +#include "uvcode.h" + +#ifndef UVSCALE +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#define log2(x) ((1./M_LN2)*log(x)) +#define exp2(x) exp(M_LN2*(x)) + +#define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \ + (int)(x) : \ + (int)((x) + rand()*(1./RAND_MAX) - .5)) + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL16toY(int p16) /* compute luminance from 16-bit LogL */ +{ + int Le = p16 & 0x7fff; + double Y; + + if (!Le) + return (0.); + Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.); + return (!(p16 & 0x8000) ? Y : -Y); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */ +{ + if (Y >= 1.8371976e19) + return (0x7fff); + if (Y <= -1.8371976e19) + return (0xffff); + if (Y > 5.4136769e-20) + return itrunc(256.*(log2(Y) + 64.), em); + if (Y < -5.4136769e-20) + return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em)); + return (0); +} + +static void +L16toY(LogLuvState* sp, tidata_t op, int n) +{ + int16* l16 = (int16*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *yp++ = (float)LogL16toY(*l16++); +} + +static void +L16toGry(LogLuvState* sp, tidata_t op, int n) +{ + int16* l16 = (int16*) sp->tbuf; + uint8* gp = (uint8*) op; + + while (n-- > 0) { + double Y = LogL16toY(*l16++); + *gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y))); + } +} + +static void +L16fromY(LogLuvState* sp, tidata_t op, int n) +{ + int16* l16 = (int16*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth)); +} + +#if !LOGLUV_PUBLIC +static +#endif +void +XYZtoRGB24(float xyz[3], uint8 rgb[3]) +{ + double r, g, b; + /* assume CCIR-709 primaries */ + r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2]; + g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2]; + b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2]; + /* assume 2.0 gamma for speed */ + /* could use integer sqrt approx., but this is probably faster */ + rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r))); + rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g))); + rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b))); +} + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL10toY(int p10) /* compute luminance from 10-bit LogL */ +{ + if (p10 == 0) + return (0.); + return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.)); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */ +{ + if (Y >= 15.742) + return (0x3ff); + else if (Y <= .00024283) + return (0); + else + return itrunc(64.*(log2(Y) + 12.), em); +} + +#define NANGLES 100 +#define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \ + * atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES ) + +static int +oog_encode(double u, double v) /* encode out-of-gamut chroma */ +{ + static int oog_table[NANGLES]; + static int initialized = 0; + register int i; + + if (!initialized) { /* set up perimeter table */ + double eps[NANGLES], ua, va, ang, epsa; + int ui, vi, ustep; + for (i = NANGLES; i--; ) + eps[i] = 2.; + for (vi = UV_NVS; vi--; ) { + va = UV_VSTART + (vi+.5)*UV_SQSIZ; + ustep = uv_row[vi].nus-1; + if (vi == UV_NVS-1 || vi == 0 || ustep <= 0) + ustep = 1; + for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) { + ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + ang = uv2ang(ua, va); + i = (int) ang; + epsa = fabs(ang - (i+.5)); + if (epsa < eps[i]) { + oog_table[i] = uv_row[vi].ncum + ui; + eps[i] = epsa; + } + } + } + for (i = NANGLES; i--; ) /* fill any holes */ + if (eps[i] > 1.5) { + int i1, i2; + for (i1 = 1; i1 < NANGLES/2; i1++) + if (eps[(i+i1)%NANGLES] < 1.5) + break; + for (i2 = 1; i2 < NANGLES/2; i2++) + if (eps[(i+NANGLES-i2)%NANGLES] < 1.5) + break; + if (i1 < i2) + oog_table[i] = + oog_table[(i+i1)%NANGLES]; + else + oog_table[i] = + oog_table[(i+NANGLES-i2)%NANGLES]; + } + initialized = 1; + } + i = (int) uv2ang(u, v); /* look up hue angle */ + return (oog_table[i]); +} + +#undef uv2ang +#undef NANGLES + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ +{ + register int vi, ui; + + if (v < UV_VSTART) + return oog_encode(u, v); + vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em); + if (vi >= UV_NVS) + return oog_encode(u, v); + if (u < uv_row[vi].ustart) + return oog_encode(u, v); + ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em); + if (ui >= uv_row[vi].nus) + return oog_encode(u, v); + + return (uv_row[vi].ncum + ui); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ +{ + int upper, lower; + register int ui, vi; + + if (c < 0 || c >= UV_NDIVS) + return (-1); + lower = 0; /* binary search */ + upper = UV_NVS; + while (upper - lower > 1) { + vi = (lower + upper) >> 1; + ui = c - uv_row[vi].ncum; + if (ui > 0) + lower = vi; + else if (ui < 0) + upper = vi; + else { + lower = vi; + break; + } + } + vi = lower; + ui = c - uv_row[vi].ncum; + *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + *vp = UV_VSTART + (vi+.5)*UV_SQSIZ; + return (0); +} + +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv24toXYZ(uint32 p, float XYZ[3]) +{ + int Ce; + double L, u, v, s, x, y; + /* decode luminance */ + L = LogL10toY(p>>14 & 0x3ff); + if (L <= 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + Ce = p & 0x3fff; + if (uv_decode(&u, &v, Ce) < 0) { + u = U_NEU; v = V_NEU; + } + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +#if !LOGLUV_PUBLIC +static +#endif +uint32 +LogLuv24fromXYZ(float XYZ[3], int em) +{ + int Le, Ce; + double u, v, s; + /* encode luminance */ + Le = LogL10fromY(XYZ[1], em); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (!Le || s <= 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + Ce = uv_encode(u, v, em); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); + /* combine encodings */ + return (Le << 14 | Ce); +} + +static void +Luv24toXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + LogLuv24toXYZ(*luv, xyz); + xyz += 3; + luv++; + } +} + +static void +Luv24toLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314); + if (uv_decode(&u, &v, *luv&0x3fff) < 0) { + u = U_NEU; + v = V_NEU; + } + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); + luv++; + } +} + +static void +Luv24toRGB(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + uint8* rgb = (uint8*) op; + + while (n-- > 0) { + float xyz[3]; + + LogLuv24toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv24fromXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth); + xyz += 3; + } +} + +static void +Luv24fromLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + int Le, Ce; + + if (luv3[0] <= 0) + Le = 0; + else if (luv3[0] >= (1<<12)+3314) + Le = (1<<10) - 1; + else if (sp->encode_meth == SGILOGENCODE_NODITHER) + Le = (luv3[0]-3314) >> 2; + else + Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth); + + Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15), + sp->encode_meth); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); + *luv++ = (uint32)Le << 14 | Ce; + luv3 += 3; + } +} + +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv32toXYZ(uint32 p, float XYZ[3]) +{ + double L, u, v, s, x, y; + /* decode luminance */ + L = LogL16toY((int)p >> 16); + if (L <= 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + u = 1./UVSCALE * ((p>>8 & 0xff) + .5); + v = 1./UVSCALE * ((p & 0xff) + .5); + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +#if !LOGLUV_PUBLIC +static +#endif +uint32 +LogLuv32fromXYZ(float XYZ[3], int em) +{ + unsigned int Le, ue, ve; + double u, v, s; + /* encode luminance */ + Le = (unsigned int)LogL16fromY(XYZ[1], em); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (!Le || s <= 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + if (u <= 0.) ue = 0; + else ue = itrunc(UVSCALE*u, em); + if (ue > 255) ue = 255; + if (v <= 0.) ve = 0; + else ve = itrunc(UVSCALE*v, em); + if (ve > 255) ve = 255; + /* combine encodings */ + return (Le << 16 | ue << 8 | ve); +} + +static void +Luv32toXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + LogLuv32toXYZ(*luv++, xyz); + xyz += 3; + } +} + +static void +Luv32toLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16)(*luv >> 16); + u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5); + v = 1./UVSCALE * ((*luv & 0xff) + .5); + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); + luv++; + } +} + +static void +Luv32toRGB(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + uint8* rgb = (uint8*) op; + + while (n-- > 0) { + float xyz[3]; + + LogLuv32toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv32fromXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth); + xyz += 3; + } +} + +static void +Luv32fromLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + if (sp->encode_meth == SGILOGENCODE_NODITHER) { + while (n-- > 0) { + *luv++ = (uint32)luv3[0] << 16 | + (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) | + (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff); + luv3 += 3; + } + return; + } + while (n-- > 0) { + *luv++ = (uint32)luv3[0] << 16 | + (itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) | + (itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff); + luv3 += 3; + } +} + +static void +_logLuvNop(LogLuvState* sp, tidata_t op, int n) +{ + (void) sp; (void) op; (void) n; +} + +static int +LogL16GuessDataFmt(TIFFDirectory *td) +{ +#define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f)) + switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) { + case PACK(1, 32, SAMPLEFORMAT_IEEEFP): + return (SGILOGDATAFMT_FLOAT); + case PACK(1, 16, SAMPLEFORMAT_VOID): + case PACK(1, 16, SAMPLEFORMAT_INT): + case PACK(1, 16, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_16BIT); + case PACK(1, 8, SAMPLEFORMAT_VOID): + case PACK(1, 8, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_8BIT); + } +#undef PACK + return (SGILOGDATAFMT_UNKNOWN); +} + +static uint32 +multiply(size_t m1, size_t m2) +{ + uint32 bytes = m1 * m2; + + if (m1 && bytes / m1 != m2) + bytes = 0; + + return bytes; +} + +static int +LogL16InitState(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + static const char module[] = "LogL16InitState"; + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGL); + + /* for some reason, we can't do this in TIFFInitLogL16 */ + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogL16GuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = sizeof (int16); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = sizeof (uint8); + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "No support for converting user data format to LogL"); + return (0); + } + if( isTiled(tif) ) + sp->tbuflen = multiply(td->td_tilewidth, td->td_tilelength); + else + sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip); + if (multiply(sp->tbuflen, sizeof (int16)) == 0 || + (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for SGILog translation buffer", + tif->tif_name); + return (0); + } + return (1); +} + +static int +LogLuvGuessDataFmt(TIFFDirectory *td) +{ + int guess; + + /* + * If the user didn't tell us their datafmt, + * take our best guess from the bitspersample. + */ +#define PACK(a,b) (((a)<<3)|(b)) + switch (PACK(td->td_bitspersample, td->td_sampleformat)) { + case PACK(32, SAMPLEFORMAT_IEEEFP): + guess = SGILOGDATAFMT_FLOAT; + break; + case PACK(32, SAMPLEFORMAT_VOID): + case PACK(32, SAMPLEFORMAT_UINT): + case PACK(32, SAMPLEFORMAT_INT): + guess = SGILOGDATAFMT_RAW; + break; + case PACK(16, SAMPLEFORMAT_VOID): + case PACK(16, SAMPLEFORMAT_INT): + case PACK(16, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_16BIT; + break; + case PACK( 8, SAMPLEFORMAT_VOID): + case PACK( 8, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_8BIT; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; +#undef PACK + } + /* + * Double-check samples per pixel. + */ + switch (td->td_samplesperpixel) { + case 1: + if (guess != SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + case 3: + if (guess == SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; + } + return (guess); +} + +static int +LogLuvInitState(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + static const char module[] = "LogLuvInitState"; + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGLUV); + + /* for some reason, we can't do this in TIFFInitLogLuv */ + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + TIFFErrorExt(tif->tif_clientdata, module, + "SGILog compression cannot handle non-contiguous data"); + return (0); + } + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogLuvGuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = 3*sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = 3*sizeof (int16); + break; + case SGILOGDATAFMT_RAW: + sp->pixel_size = sizeof (uint32); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = 3*sizeof (uint8); + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "No support for converting user data format to LogLuv"); + return (0); + } + if( isTiled(tif) ) + sp->tbuflen = multiply(td->td_tilewidth, td->td_tilelength); + else + sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip); + if (multiply(sp->tbuflen, sizeof (uint32)) == 0 || + (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for SGILog translation buffer", + tif->tif_name); + return (0); + } + return (1); +} + +static int +LogLuvSetupDecode(TIFF* tif) +{ + LogLuvState* sp = DecoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + tif->tif_postdecode = _TIFFNoPostDecode; + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_decoderow = LogLuvDecode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv24toRGB; + break; + } + } else { + tif->tif_decoderow = LogLuvDecode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv32toRGB; + break; + } + } + return (1); + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_decoderow = LogL16Decode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16toY; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = L16toGry; + break; + } + return (1); + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Inappropriate photometric interpretation %d for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (0); +} + +static int +LogLuvSetupEncode(TIFF* tif) +{ + LogLuvState* sp = EncoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_encoderow = LogLuvEncode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } else { + tif->tif_encoderow = LogLuvEncode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } + break; + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_encoderow = LogL16Encode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16fromY; + break; + case SGILOGDATAFMT_16BIT: + break; + default: + goto notsupported; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Inappropriate photometric interpretation %d for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (1); +notsupported: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "SGILog compression supported only for %s, or raw data", + td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv"); + return (0); +} + +static void +LogLuvClose(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + + /* + * For consistency, we always want to write out the same + * bitspersample and sampleformat for our TIFF file, + * regardless of the data format being used by the application. + * Since this routine is called after tags have been set but + * before they have been recorded in the file, we reset them here. + */ + td->td_samplesperpixel = + (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3; + td->td_bitspersample = 16; + td->td_sampleformat = SAMPLEFORMAT_INT; +} + +static void +LogLuvCleanup(TIFF* tif) +{ + LogLuvState* sp = (LogLuvState *)tif->tif_data; + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + LogLuvState* sp = DecoderState(tif); + int bps, fmt; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + sp->user_datafmt = va_arg(ap, int); + /* + * Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + bps = 32, fmt = SAMPLEFORMAT_IEEEFP; + break; + case SGILOGDATAFMT_16BIT: + bps = 16, fmt = SAMPLEFORMAT_INT; + break; + case SGILOGDATAFMT_RAW: + bps = 32, fmt = SAMPLEFORMAT_UINT; + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + break; + case SGILOGDATAFMT_8BIT: + bps = 8, fmt = SAMPLEFORMAT_UINT; + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Unknown data format %d for LogLuv compression", + sp->user_datafmt); + return (0); + } + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt); + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1; + tif->tif_scanlinesize = TIFFScanlineSize(tif); + return (1); + case TIFFTAG_SGILOGENCODE: + sp->encode_meth = va_arg(ap, int); + if (sp->encode_meth != SGILOGENCODE_NODITHER && + sp->encode_meth != SGILOGENCODE_RANDITHER) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Unknown encoding %d for LogLuv compression", + sp->encode_meth); + return (0); + } + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } +} + +static int +LogLuvVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + LogLuvState *sp = (LogLuvState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + return (1); + default: + return (*sp->vgetparent)(tif, tag, ap); + } +} + +static const TIFFFieldInfo LogLuvFieldInfo[] = { + { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, FIELD_PSEUDO, + TRUE, FALSE, "SGILogDataFmt"}, + { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, FIELD_PSEUDO, + TRUE, FALSE, "SGILogEncode"} +}; + +int +TIFFInitSGILog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitSGILog"; + LogLuvState* sp; + + assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, LogLuvFieldInfo, + TIFFArrayCount(LogLuvFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging SGILog codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LogLuvState)); + if (tif->tif_data == NULL) + goto bad; + sp = (LogLuvState*) tif->tif_data; + _TIFFmemset((tdata_t)sp, 0, sizeof (*sp)); + sp->user_datafmt = SGILOGDATAFMT_UNKNOWN; + sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ? + SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER; + sp->tfunc = _logLuvNop; + + /* + * Install codec methods. + * NB: tif_decoderow & tif_encoderow are filled + * in at setup time. + */ + tif->tif_setupdecode = LogLuvSetupDecode; + tif->tif_decodestrip = LogLuvDecodeStrip; + tif->tif_decodetile = LogLuvDecodeTile; + tif->tif_setupencode = LogLuvSetupEncode; + tif->tif_encodestrip = LogLuvEncodeStrip; + tif->tif_encodetile = LogLuvEncodeTile; + tif->tif_close = LogLuvClose; + tif->tif_cleanup = LogLuvCleanup; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */ + + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "%s: No space for LogLuv state block", tif->tif_name); + return (0); +} +#endif /* LOGLUV_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_lzw.c b/thirdparty/libtiff/tif_lzw.c new file mode 100644 index 00000000..d4238663 --- /dev/null +++ b/thirdparty/libtiff/tif_lzw.c @@ -0,0 +1,1129 @@ +/* $Id: tif_lzw.c,v 1.29.2.6 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LZW_SUPPORT +/* + * TIFF Library. + * Rev 5.0 Lempel-Ziv & Welch Compression Support + * + * This code is derived from the compress program whose code is + * derived from software contributed to Berkeley by James A. Woods, + * derived from original work by Spencer Thomas and Joseph Orost. + * + * The original Berkeley copyright notice appears below in its entirety. + */ +#include "tif_predict.h" + +#include + +/* + * NB: The 5.0 spec describes a different algorithm than Aldus + * implements. Specifically, Aldus does code length transitions + * one code earlier than should be done (for real LZW). + * Earlier versions of this library implemented the correct + * LZW algorithm, but emitted codes in a bit order opposite + * to the TIFF spec. Thus, to maintain compatibility w/ Aldus + * we interpret MSB-LSB ordered codes to be images written w/ + * old versions of this library, but otherwise adhere to the + * Aldus "off by one" algorithm. + * + * Future revisions to the TIFF spec are expected to "clarify this issue". + */ +#define LZW_COMPAT /* include backwards compatibility code */ +/* + * Each strip of data is supposed to be terminated by a CODE_EOI. + * If the following #define is included, the decoder will also + * check for end-of-strip w/o seeing this code. This makes the + * library more robust, but also slower. + */ +#define LZW_CHECKEOS /* include checks for strips w/o EOI code */ + +#define MAXCODE(n) ((1L<<(n))-1) +/* + * The TIFF spec specifies that encoded bit + * strings range from 9 to 12 bits. + */ +#define BITS_MIN 9 /* start with 9 bits */ +#define BITS_MAX 12 /* max of 12 bit strings */ +/* predefined codes */ +#define CODE_CLEAR 256 /* code to clear string table */ +#define CODE_EOI 257 /* end-of-information code */ +#define CODE_FIRST 258 /* first free code entry */ +#define CODE_MAX MAXCODE(BITS_MAX) +#define HSIZE 9001L /* 91% occupancy */ +#define HSHIFT (13-8) +#ifdef LZW_COMPAT +/* NB: +1024 is for compatibility with old files */ +#define CSIZE (MAXCODE(BITS_MAX)+1024L) +#else +#define CSIZE (MAXCODE(BITS_MAX)+1L) +#endif + +/* + * State block for each open TIFF file using LZW + * compression/decompression. Note that the predictor + * state block must be first in this data structure. + */ +typedef struct { + TIFFPredictorState predict; /* predictor super class */ + + unsigned short nbits; /* # of bits/code */ + unsigned short maxcode; /* maximum code for lzw_nbits */ + unsigned short free_ent; /* next free entry in hash table */ + long nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in lzw_nextdata */ + + int rw_mode; /* preserve rw_mode from init */ +} LZWBaseState; + +#define lzw_nbits base.nbits +#define lzw_maxcode base.maxcode +#define lzw_free_ent base.free_ent +#define lzw_nextdata base.nextdata +#define lzw_nextbits base.nextbits + +/* + * Encoding-specific state. + */ +typedef uint16 hcode_t; /* codes fit in 16 bits */ +typedef struct { + long hash; + hcode_t code; +} hash_t; + +/* + * Decoding-specific state. + */ +typedef struct code_ent { + struct code_ent *next; + unsigned short length; /* string len, including this token */ + unsigned char value; /* data value */ + unsigned char firstchar; /* first token of string */ +} code_t; + +typedef int (*decodeFunc)(TIFF*, tidata_t, tsize_t, tsample_t); + +typedef struct { + LZWBaseState base; + + /* Decoding specific data */ + long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */ + long dec_restart; /* restart count */ +#ifdef LZW_CHECKEOS + long dec_bitsleft; /* available bits in raw data */ +#endif + decodeFunc dec_decode; /* regular or backwards compatible */ + code_t* dec_codep; /* current recognized code */ + code_t* dec_oldcodep; /* previously recognized code */ + code_t* dec_free_entp; /* next free entry */ + code_t* dec_maxcodep; /* max available entry */ + code_t* dec_codetab; /* kept separate for small machines */ + + /* Encoding specific data */ + int enc_oldcode; /* last code encountered */ + long enc_checkpoint; /* point at which to clear table */ +#define CHECK_GAP 10000 /* enc_ratio check interval */ + long enc_ratio; /* current compression ratio */ + long enc_incount; /* (input) data bytes encoded */ + long enc_outcount; /* encoded (output) bytes */ + tidata_t enc_rawlimit; /* bound on tif_rawdata buffer */ + hash_t* enc_hashtab; /* kept separate for small machines */ +} LZWCodecState; + +#define LZWState(tif) ((LZWBaseState*) (tif)->tif_data) +#define DecoderState(tif) ((LZWCodecState*) LZWState(tif)) +#define EncoderState(tif) ((LZWCodecState*) LZWState(tif)) + +static int LZWDecode(TIFF*, tidata_t, tsize_t, tsample_t); +#ifdef LZW_COMPAT +static int LZWDecodeCompat(TIFF*, tidata_t, tsize_t, tsample_t); +#endif +static void cl_hash(LZWCodecState*); + +/* + * LZW Decoder. + */ + +#ifdef LZW_CHECKEOS +/* + * This check shouldn't be necessary because each + * strip is suppose to be terminated with CODE_EOI. + */ +#define NextCode(_tif, _sp, _bp, _code, _get) { \ + if ((_sp)->dec_bitsleft < nbits) { \ + TIFFWarningExt(_tif->tif_clientdata, _tif->tif_name, \ + "LZWDecode: Strip %d not terminated with EOI code", \ + _tif->tif_curstrip); \ + _code = CODE_EOI; \ + } else { \ + _get(_sp,_bp,_code); \ + (_sp)->dec_bitsleft -= nbits; \ + } \ +} +#else +#define NextCode(tif, sp, bp, code, get) get(sp, bp, code) +#endif + +static int +LZWSetupDecode(TIFF* tif) +{ + LZWCodecState* sp = DecoderState(tif); + static const char module[] = " LZWSetupDecode"; + int code; + + if( sp == NULL ) + { + /* + * Allocate state block so tag methods have storage to record + * values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof(LZWCodecState)); + if (tif->tif_data == NULL) + { + TIFFErrorExt(tif->tif_clientdata, "LZWPreDecode", "No space for LZW state block"); + return (0); + } + + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + + sp = DecoderState(tif); + } + + assert(sp != NULL); + + if (sp->dec_codetab == NULL) { + sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t)); + if (sp->dec_codetab == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW code table"); + return (0); + } + /* + * Pre-load the table. + */ + code = 255; + do { + sp->dec_codetab[code].value = code; + sp->dec_codetab[code].firstchar = code; + sp->dec_codetab[code].length = 1; + sp->dec_codetab[code].next = NULL; + } while (code--); + /* + * Zero-out the unused entries + */ + _TIFFmemset(&sp->dec_codetab[CODE_CLEAR], 0, + (CODE_FIRST - CODE_CLEAR) * sizeof (code_t)); + } + return (1); +} + +/* + * Setup state for decoding a strip. + */ +static int +LZWPreDecode(TIFF* tif, tsample_t s) +{ + LZWCodecState *sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->dec_codetab == NULL ) + { + tif->tif_setupdecode( tif ); + } + + /* + * Check for old bit-reversed codes. + */ + if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) { +#ifdef LZW_COMPAT + if (!sp->dec_decode) { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Old-style LZW codes, convert file"); + /* + * Override default decoding methods with + * ones that deal with the old coding. + * Otherwise the predictor versions set + * above will call the compatibility routines + * through the dec_decode method. + */ + tif->tif_decoderow = LZWDecodeCompat; + tif->tif_decodestrip = LZWDecodeCompat; + tif->tif_decodetile = LZWDecodeCompat; + /* + * If doing horizontal differencing, must + * re-setup the predictor logic since we + * switched the basic decoder methods... + */ + (*tif->tif_setupdecode)(tif); + sp->dec_decode = LZWDecodeCompat; + } + sp->lzw_maxcode = MAXCODE(BITS_MIN); +#else /* !LZW_COMPAT */ + if (!sp->dec_decode) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Old-style LZW codes not supported"); + sp->dec_decode = LZWDecode; + } + return (0); +#endif/* !LZW_COMPAT */ + } else { + sp->lzw_maxcode = MAXCODE(BITS_MIN)-1; + sp->dec_decode = LZWDecode; + } + sp->lzw_nbits = BITS_MIN; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + + sp->dec_restart = 0; + sp->dec_nbitsmask = MAXCODE(BITS_MIN); +#ifdef LZW_CHECKEOS + sp->dec_bitsleft = tif->tif_rawcc << 3; +#endif + sp->dec_free_entp = sp->dec_codetab + CODE_FIRST; + /* + * Zero entries that are not yet filled in. We do + * this to guard against bogus input data that causes + * us to index into undefined entries. If you can + * come up with a way to safely bounds-check input codes + * while decoding then you can remove this operation. + */ + _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t)); + sp->dec_oldcodep = &sp->dec_codetab[-1]; + sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1]; + return (1); +} + +/* + * Decode a "hunk of data". + */ +#define GetNextCode(sp, bp, code) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + } \ + code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask); \ + nextbits -= nbits; \ +} + +static void +codeLoop(TIFF* tif) +{ + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Bogus encoding, loop in the code table; scanline %d", + tif->tif_row); +} + +static int +LZWDecode(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + LZWCodecState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + hcode_t code; + int len; + long nbits, nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + assert(sp->dec_codetab != NULL); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ && codep); + if (codep) { + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + } + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (--residue && codep); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask-1; + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + *op++ = (char)code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + if (free_entp < &sp->dec_codetab[0] || + free_entp >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + + free_entp->next = oldcodep; + if (free_entp->next < &sp->dec_codetab[0] || + free_entp->next >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask-1; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if(codep->length == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Wrong length of decoded string: " + "data probably corrupted at scanline %d", + tif->tif_row); + return (0); + } + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep && codep->length > occ); + if (codep) { + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + if (codep) + codeLoop(tif); + } + break; + } + len = codep->length; + tp = op + len; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (codep && tp > op); + if (codep) { + codeLoop(tif); + break; + } + op += len, occ -= len; + } else + *op++ = (char)code, occ--; + } + + tif->tif_rawcp = (tidata_t) bp; + sp->lzw_nbits = (unsigned short) nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Not enough data at scanline %d (short %ld bytes)", + tif->tif_row, occ); + return (0); + } + return (1); +} + +#ifdef LZW_COMPAT +/* + * Decode a "hunk of data" for old images. + */ +#define GetNextCodeCompat(sp, bp, code) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits;\ + nextbits += 8; \ + } \ + code = (hcode_t)(nextdata & nbitsmask); \ + nextdata >>= nbits; \ + nextbits -= nbits; \ +} + +static int +LZWDecodeCompat(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + LZWCodecState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + int code, nbits; + long nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ); + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + *--tp = codep->value; + codep = codep->next; + } while (--residue); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask; + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + *op++ = code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + if (free_entp < &sp->dec_codetab[0] || + free_entp >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecodeCompat: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + + free_entp->next = oldcodep; + if (free_entp->next < &sp->dec_codetab[0] || + free_entp->next >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecodeCompat: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask; + } + oldcodep = codep; + if (code >= 256) { + char *op_orig = op; + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if(codep->length == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecodeCompat: Wrong length of decoded " + "string: data probably corrupted at scanline %d", + tif->tif_row); + return (0); + } + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep->length > occ); + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + break; + } + op += codep->length, occ -= codep->length; + tp = op; + do { + *--tp = codep->value; + } while( (codep = codep->next) != NULL && tp > op_orig); + } else + *op++ = code, occ--; + } + + tif->tif_rawcp = (tidata_t) bp; + sp->lzw_nbits = nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecodeCompat: Not enough data at scanline %d (short %ld bytes)", + tif->tif_row, occ); + return (0); + } + return (1); +} +#endif /* LZW_COMPAT */ + +/* + * LZW Encoding. + */ + +static int +LZWSetupEncode(TIFF* tif) +{ + LZWCodecState* sp = EncoderState(tif); + static const char module[] = "LZWSetupEncode"; + + assert(sp != NULL); + sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t)); + if (sp->enc_hashtab == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for LZW hash table"); + return (0); + } + return (1); +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +LZWPreEncode(TIFF* tif, tsample_t s) +{ + LZWCodecState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + + if( sp->enc_hashtab == NULL ) + { + tif->tif_setupencode( tif ); + } + + sp->lzw_nbits = BITS_MIN; + sp->lzw_maxcode = MAXCODE(BITS_MIN); + sp->lzw_free_ent = CODE_FIRST; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + sp->enc_checkpoint = CHECK_GAP; + sp->enc_ratio = 0; + sp->enc_incount = 0; + sp->enc_outcount = 0; + /* + * The 4 here insures there is space for 2 max-sized + * codes in LZWEncode and LZWPostDecode. + */ + sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4; + cl_hash(sp); /* clear hash table */ + sp->enc_oldcode = (hcode_t) -1; /* generates CODE_CLEAR in LZWEncode */ + return (1); +} + +#define CALCRATIO(sp, rat) { \ + if (incount > 0x007fffff) { /* NB: shift will overflow */\ + rat = outcount >> 8; \ + rat = (rat == 0 ? 0x7fffffff : incount/rat); \ + } else \ + rat = (incount<<8) / outcount; \ +} +#define PutNextCode(op, c) { \ + nextdata = (nextdata << nbits) | c; \ + nextbits += nbits; \ + *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ + nextbits -= 8; \ + if (nextbits >= 8) { \ + *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ + nextbits -= 8; \ + } \ + outcount += nbits; \ +} + +/* + * Encode a chunk of pixels. + * + * Uses an open addressing double hashing (no chaining) on the + * prefix code/next character combination. We do a variant of + * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's + * relatively-prime secondary probe. Here, the modular division + * first probe is gives way to a faster exclusive-or manipulation. + * Also do block compression with an adaptive reset, whereby the + * code table is cleared when the compression ratio decreases, + * but after the table fills. The variable-length output codes + * are re-sized at this point, and a CODE_CLEAR is generated + * for the decoder. + */ +static int +LZWEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + register LZWCodecState *sp = EncoderState(tif); + register long fcode; + register hash_t *hp; + register int h, c; + hcode_t ent; + long disp; + long incount, outcount, checkpoint; + long nextdata, nextbits; + int free_ent, maxcode, nbits; + tidata_t op, limit; + + (void) s; + if (sp == NULL) + return (0); + + assert(sp->enc_hashtab != NULL); + + /* + * Load local state. + */ + incount = sp->enc_incount; + outcount = sp->enc_outcount; + checkpoint = sp->enc_checkpoint; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + free_ent = sp->lzw_free_ent; + maxcode = sp->lzw_maxcode; + nbits = sp->lzw_nbits; + op = tif->tif_rawcp; + limit = sp->enc_rawlimit; + ent = sp->enc_oldcode; + + if (ent == (hcode_t) -1 && cc > 0) { + /* + * NB: This is safe because it can only happen + * at the start of a strip where we know there + * is space in the data buffer. + */ + PutNextCode(op, CODE_CLEAR); + ent = *bp++; cc--; incount++; + } + while (cc > 0) { + c = *bp++; cc--; incount++; + fcode = ((long)c << BITS_MAX) + ent; + h = (c << HSHIFT) ^ ent; /* xor hashing */ +#ifdef _WINDOWS + /* + * Check hash index for an overflow. + */ + if (h >= HSIZE) + h -= HSIZE; +#endif + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + continue; + } + if (hp->hash >= 0) { + /* + * Primary hash failed, check secondary hash. + */ + disp = HSIZE - h; + if (h == 0) + disp = 1; + do { + /* + * Avoid pointer arithmetic 'cuz of + * wraparound problems with segments. + */ + if ((h -= disp) < 0) + h += HSIZE; + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + goto hit; + } + } while (hp->hash >= 0); + } + /* + * New entry, emit code and add to table. + */ + /* + * Verify there is space in the buffer for the code + * and any potential Clear code that might be emitted + * below. The value of limit is setup so that there + * are at least 4 bytes free--room for 2 codes. + */ + if (op > limit) { + tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); + TIFFFlushData1(tif); + op = tif->tif_rawdata; + } + PutNextCode(op, ent); + ent = c; + hp->code = free_ent++; + hp->hash = fcode; + if (free_ent == CODE_MAX-1) { + /* table is full, emit clear code and reset */ + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + maxcode = (int) MAXCODE(nbits); + } else if (incount >= checkpoint) { + long rat; + /* + * Check compression ratio and, if things seem + * to be slipping, clear the hash table and + * reset state. The compression ratio is a + * 24+8-bit fractional number. + */ + checkpoint = incount+CHECK_GAP; + CALCRATIO(sp, rat); + if (rat <= sp->enc_ratio) { + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else + sp->enc_ratio = rat; + } + } + hit: + ; + } + + /* + * Restore global state. + */ + sp->enc_incount = incount; + sp->enc_outcount = outcount; + sp->enc_checkpoint = checkpoint; + sp->enc_oldcode = ent; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->lzw_free_ent = free_ent; + sp->lzw_maxcode = maxcode; + sp->lzw_nbits = nbits; + tif->tif_rawcp = op; + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +LZWPostEncode(TIFF* tif) +{ + register LZWCodecState *sp = EncoderState(tif); + tidata_t op = tif->tif_rawcp; + long nextbits = sp->lzw_nextbits; + long nextdata = sp->lzw_nextdata; + long outcount = sp->enc_outcount; + int nbits = sp->lzw_nbits; + + if (op > sp->enc_rawlimit) { + tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); + TIFFFlushData1(tif); + op = tif->tif_rawdata; + } + if (sp->enc_oldcode != (hcode_t) -1) { + PutNextCode(op, sp->enc_oldcode); + sp->enc_oldcode = (hcode_t) -1; + } + PutNextCode(op, CODE_EOI); + if (nextbits > 0) + *op++ = (unsigned char)(nextdata << (8-nextbits)); + tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); + return (1); +} + +/* + * Reset encoding hash table. + */ +static void +cl_hash(LZWCodecState* sp) +{ + register hash_t *hp = &sp->enc_hashtab[HSIZE-1]; + register long i = HSIZE-8; + + do { + i -= 8; + hp[-7].hash = -1; + hp[-6].hash = -1; + hp[-5].hash = -1; + hp[-4].hash = -1; + hp[-3].hash = -1; + hp[-2].hash = -1; + hp[-1].hash = -1; + hp[ 0].hash = -1; + hp -= 8; + } while (i >= 0); + for (i += 8; i > 0; i--, hp--) + hp->hash = -1; +} + +static void +LZWCleanup(TIFF* tif) +{ + (void)TIFFPredictorCleanup(tif); + + assert(tif->tif_data != 0); + + if (DecoderState(tif)->dec_codetab) + _TIFFfree(DecoderState(tif)->dec_codetab); + + if (EncoderState(tif)->enc_hashtab) + _TIFFfree(EncoderState(tif)->enc_hashtab); + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +int +TIFFInitLZW(TIFF* tif, int scheme) +{ + assert(scheme == COMPRESSION_LZW); + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LZWCodecState)); + if (tif->tif_data == NULL) + goto bad; + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + EncoderState(tif)->enc_hashtab = NULL; + LZWState(tif)->rw_mode = tif->tif_mode; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = LZWSetupDecode; + tif->tif_predecode = LZWPreDecode; + tif->tif_decoderow = LZWDecode; + tif->tif_decodestrip = LZWDecode; + tif->tif_decodetile = LZWDecode; + tif->tif_setupencode = LZWSetupEncode; + tif->tif_preencode = LZWPreEncode; + tif->tif_postencode = LZWPostEncode; + tif->tif_encoderow = LZWEncode; + tif->tif_encodestrip = LZWEncode; + tif->tif_encodetile = LZWEncode; + tif->tif_cleanup = LZWCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, "TIFFInitLZW", + "No space for LZW state block"); + return (0); +} + +/* + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#endif /* LZW_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_next.c b/thirdparty/libtiff/tif_next.c new file mode 100644 index 00000000..d7652bb4 --- /dev/null +++ b/thirdparty/libtiff/tif_next.c @@ -0,0 +1,154 @@ +/* $Id: tif_next.c,v 1.8.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef NEXT_SUPPORT +/* + * TIFF Library. + * + * NeXT 2-bit Grey Scale Compression Algorithm Support + */ + +#define SETPIXEL(op, v) { \ + switch (npixels++ & 3) { \ + case 0: op[0] = (unsigned char) ((v) << 6); break; \ + case 1: op[0] |= (v) << 4; break; \ + case 2: op[0] |= (v) << 2; break; \ + case 3: *op++ |= (v); break; \ + } \ +} + +#define LITERALROW 0x00 +#define LITERALSPAN 0x40 +#define WHITE ((1<<2)-1) + +static int +NeXTDecode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + unsigned char *bp, *op; + tsize_t cc; + tidata_t row; + tsize_t scanline, n; + + (void) s; + /* + * Each scanline is assumed to start off as all + * white (we assume a PhotometricInterpretation + * of ``min-is-black''). + */ + for (op = buf, cc = occ; cc-- > 0;) + *op++ = 0xff; + + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + scanline = tif->tif_scanlinesize; + for (row = buf; occ > 0; occ -= scanline, row += scanline) { + n = *bp++, cc--; + switch (n) { + case LITERALROW: + /* + * The entire scanline is given as literal values. + */ + if (cc < scanline) + goto bad; + _TIFFmemcpy(row, bp, scanline); + bp += scanline; + cc -= scanline; + break; + case LITERALSPAN: { + tsize_t off; + /* + * The scanline has a literal span that begins at some + * offset. + */ + off = (bp[0] * 256) + bp[1]; + n = (bp[2] * 256) + bp[3]; + if (cc < 4+n || off+n > scanline) + goto bad; + _TIFFmemcpy(row+off, bp+4, n); + bp += 4+n; + cc -= 4+n; + break; + } + default: { + uint32 npixels = 0, grey; + uint32 imagewidth = tif->tif_dir.td_imagewidth; + + /* + * The scanline is composed of a sequence of constant + * color ``runs''. We shift into ``run mode'' and + * interpret bytes as codes of the form + * until we've filled the scanline. + */ + op = row; + for (;;) { + grey = (n>>6) & 0x3; + n &= 0x3f; + /* + * Ensure the run does not exceed the scanline + * bounds, potentially resulting in a security + * issue. + */ + while (n-- > 0 && npixels < imagewidth) + SETPIXEL(op, grey); + if (npixels >= imagewidth) + break; + if (cc == 0) + goto bad; + n = *bp++, cc--; + } + break; + } + } + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "NeXTDecode: Not enough data for scanline %ld", + (long) tif->tif_row); + return (0); +} + +int +TIFFInitNeXT(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = NeXTDecode; + tif->tif_decodestrip = NeXTDecode; + tif->tif_decodetile = NeXTDecode; + return (1); +} +#endif /* NEXT_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_ojpeg.c b/thirdparty/libtiff/tif_ojpeg.c new file mode 100644 index 00000000..9ae856cf --- /dev/null +++ b/thirdparty/libtiff/tif_ojpeg.c @@ -0,0 +1,2438 @@ +/* $Id: tif_ojpeg.c,v 1.24.2.6 2010-06-08 23:29:51 bfriesen Exp $ */ + +/* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0 + specification is now totally obsolete and deprecated for new applications and + images. This file was was created solely in order to read unconverted images + still present on some users' computer systems. It will never be extended + to write such files. Writing new-style JPEG compressed TIFFs is implemented + in tif_jpeg.c. + + The code is carefully crafted to robustly read all gathered JPEG-in-TIFF + testfiles, and anticipate as much as possible all other... But still, it may + fail on some. If you encounter problems, please report them on the TIFF + mailing list and/or to Joris Van Damme . + + Please read the file called "TIFF Technical Note #2" if you need to be + convinced this compression scheme is bad and breaks TIFF. That document + is linked to from the LibTiff site + and from AWare Systems' TIFF section + . It is also absorbed + in Adobe's specification supplements, marked "draft" up to this day, but + supported by the TIFF community. + + This file interfaces with Release 6B of the JPEG Library written by the + Independent JPEG Group. Previous versions of this file required a hack inside + the LibJpeg library. This version no longer requires that. Remember to + remove the hack if you update from the old version. + + Copyright (c) Joris Van Damme + Copyright (c) AWare Systems + + The licence agreement for this file is the same as the rest of the LibTiff + library. + + IN NO EVENT SHALL JORIS VAN DAMME OR AWARE SYSTEMS BE LIABLE FOR + ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + OF THIS SOFTWARE. + + Joris Van Damme and/or AWare Systems may be available for custom + developement. If you like what you see, and need anything similar or related, + contact . +*/ + +/* What is what, and what is not? + + This decoder starts with an input stream, that is essentially the JpegInterchangeFormat + stream, if any, followed by the strile data, if any. This stream is read in + OJPEGReadByte and related functions. + + It analyzes the start of this stream, until it encounters non-marker data, i.e. + compressed image data. Some of the header markers it sees have no actual content, + like the SOI marker, and APP/COM markers that really shouldn't even be there. Some + other markers do have content, and the valuable bits and pieces of information + in these markers are saved, checking all to verify that the stream is more or + less within expected bounds. This happens inside the OJPEGReadHeaderInfoSecStreamXxx + functions. + + Some OJPEG imagery contains no valid JPEG header markers. This situation is picked + up on if we've seen no SOF marker when we're at the start of the compressed image + data. In this case, the tables are read from JpegXxxTables tags, and the other + bits and pieces of information is initialized to its most basic value. This is + implemented in the OJPEGReadHeaderInfoSecTablesXxx functions. + + When this is complete, a good and valid JPEG header can be assembled, and this is + passed through to LibJpeg. When that's done, the remainder of the input stream, i.e. + the compressed image data, can be passed through unchanged. This is done in + OJPEGWriteStream functions. + + LibTiff rightly expects to know the subsampling values before decompression. Just like + in new-style JPEG-in-TIFF, though, or even more so, actually, the YCbCrsubsampling + tag is notoriously unreliable. To correct these tag values with the ones inside + the JPEG stream, the first part of the input stream is pre-scanned in + OJPEGSubsamplingCorrect, making no note of any other data, reporting no warnings + or errors, up to the point where either these values are read, or it's clear they + aren't there. This means that some of the data is read twice, but we feel speed + in correcting these values is important enough to warrant this sacrifice. Allthough + there is currently no define or other configuration mechanism to disable this behaviour, + the actual header scanning is build to robustly respond with error report if it + should encounter an uncorrected mismatch of subsampling values. See + OJPEGReadHeaderInfoSecStreamSof. + + The restart interval and restart markers are the most tricky part... The restart + interval can be specified in a tag. It can also be set inside the input JPEG stream. + It can be used inside the input JPEG stream. If reading from strile data, we've + consistenly discovered the need to insert restart markers in between the different + striles, as is also probably the most likely interpretation of the original TIFF 6.0 + specification. With all this setting of interval, and actual use of markers that is not + predictable at the time of valid JPEG header assembly, the restart thing may turn + out the Achilles heel of this implementation. Fortunately, most OJPEG writer vendors + succeed in reading back what they write, which may be the reason why we've been able + to discover ways that seem to work. + + Some special provision is made for planarconfig separate OJPEG files. These seem + to consistently contain header info, a SOS marker, a plane, SOS marker, plane, SOS, + and plane. This may or may not be a valid JPEG configuration, we don't know and don't + care. We want LibTiff to be able to access the planes individually, without huge + buffering inside LibJpeg, anyway. So we compose headers to feed to LibJpeg, in this + case, that allow us to pass a single plane such that LibJpeg sees a valid + single-channel JPEG stream. Locating subsequent SOS markers, and thus subsequent + planes, is done inside OJPEGReadSecondarySos. + + The benefit of the scheme is... that it works, basically. We know of no other that + does. It works without checking software tag, or otherwise going about things in an + OJPEG flavor specific manner. Instead, it is a single scheme, that covers the cases + with and without JpegInterchangeFormat, with and without striles, with part of + the header in JpegInterchangeFormat and remainder in first strile, etc. It is forgiving + and robust, may likely work with OJPEG flavors we've not seen yet, and makes most out + of the data. + + Another nice side-effect is that a complete JPEG single valid stream is build if + planarconfig is not separate (vast majority). We may one day use that to build + converters to JPEG, and/or to new-style JPEG compression inside TIFF. + + A dissadvantage is the lack of random access to the individual striles. This is the + reason for much of the complicated restart-and-position stuff inside OJPEGPreDecode. + Applications would do well accessing all striles in order, as this will result in + a single sequential scan of the input stream, and no restarting of LibJpeg decoding + session. +*/ + + +#include "tiffiop.h" +#ifdef OJPEG_SUPPORT + +/* Configuration defines here are: + * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some environments, + * like eg LibTiffDelphi, this is not possible. For this reason, the actual calls to + * libjpeg, with longjump stuff, are encapsulated in dedicated functions. When + * JPEG_ENCAP_EXTERNAL is defined, these encapsulating functions are declared external + * to this unit, and can be defined elsewhere to use stuff other then longjump. + * The default mode, without JPEG_ENCAP_EXTERNAL, implements the call encapsulators + * here, internally, with normal longjump. + * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent is + * conviniently available, but still it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. It is useless + * to fiddle with these if you define JPEG_ENCAP_EXTERNAL. + * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee + * instant processing, optimal streaming and optimal use of processor cache, but also big + * enough so as to not result in significant call overhead. It should be at least a few + * bytes to accomodate some structures (this is verified in asserts), but it would not be + * sensible to make it this small anyway, and it should be at most 64K since it is indexed + * with uint16. We recommend 2K. + * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has + * absolutely no effect. That is why most people insist the EGYPTIANWALK is a bit silly. + */ + +/* #define LIBJPEG_ENCAP_EXTERNAL */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf +#define OJPEG_BUFFER 2048 +/* define EGYPTIANWALK */ + +#define JPEG_MARKER_SOF0 0xC0 +#define JPEG_MARKER_SOF1 0xC1 +#define JPEG_MARKER_SOF3 0xC3 +#define JPEG_MARKER_DHT 0xC4 +#define JPEG_MARKER_RST0 0XD0 +#define JPEG_MARKER_SOI 0xD8 +#define JPEG_MARKER_EOI 0xD9 +#define JPEG_MARKER_SOS 0xDA +#define JPEG_MARKER_DQT 0xDB +#define JPEG_MARKER_DRI 0xDD +#define JPEG_MARKER_APP0 0xE0 +#define JPEG_MARKER_COM 0xFE + +#define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC+0) +#define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC+1) +#define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC+2) +#define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC+3) +#define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC+4) +#define FIELD_OJPEG_JPEGPROC (FIELD_CODEC+5) +#define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC+6) +#define FIELD_OJPEG_COUNT 7 + +static const TIFFFieldInfo ojpeg_field_info[] = { + {TIFFTAG_JPEGIFOFFSET,1,1,TIFF_LONG,FIELD_OJPEG_JPEGINTERCHANGEFORMAT,TRUE,FALSE,"JpegInterchangeFormat"}, + {TIFFTAG_JPEGIFBYTECOUNT,1,1,TIFF_LONG,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH,TRUE,FALSE,"JpegInterchangeFormatLength"}, + {TIFFTAG_JPEGQTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGQTABLES,FALSE,TRUE,"JpegQTables"}, + {TIFFTAG_JPEGDCTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGDCTABLES,FALSE,TRUE,"JpegDcTables"}, + {TIFFTAG_JPEGACTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGACTABLES,FALSE,TRUE,"JpegAcTables"}, + {TIFFTAG_JPEGPROC,1,1,TIFF_SHORT,FIELD_OJPEG_JPEGPROC,FALSE,FALSE,"JpegProc"}, + {TIFFTAG_JPEGRESTARTINTERVAL,1,1,TIFF_SHORT,FIELD_OJPEG_JPEGRESTARTINTERVAL,FALSE,FALSE,"JpegRestartInterval"}, +}; + +#ifndef LIBJPEG_ENCAP_EXTERNAL +#include +#endif + +#include "jpeglib.h" +#include "jerror.h" + +typedef struct jpeg_error_mgr jpeg_error_mgr; +typedef struct jpeg_common_struct jpeg_common_struct; +typedef struct jpeg_decompress_struct jpeg_decompress_struct; +typedef struct jpeg_source_mgr jpeg_source_mgr; + +typedef enum { + osibsNotSetYet, + osibsJpegInterchangeFormat, + osibsStrile, + osibsEof +} OJPEGStateInBufferSource; + +typedef enum { + ososSoi, + ososQTable0,ososQTable1,ososQTable2,ososQTable3, + ososDcTable0,ososDcTable1,ososDcTable2,ososDcTable3, + ososAcTable0,ososAcTable1,ososAcTable2,ososAcTable3, + ososDri, + ososSof, + ososSos, + ososCompressed, + ososRst, + ososEoi +} OJPEGStateOutState; + +typedef struct { + TIFF* tif; + #ifndef LIBJPEG_ENCAP_EXTERNAL + JMP_BUF exit_jmpbuf; + #endif + TIFFVGetMethod vgetparent; + TIFFVSetMethod vsetparent; + toff_t file_size; + uint32 image_width; + uint32 image_length; + uint32 strile_width; + uint32 strile_length; + uint32 strile_length_total; + uint8 samples_per_pixel; + uint8 plane_sample_offset; + uint8 samples_per_pixel_per_plane; + toff_t jpeg_interchange_format; + toff_t jpeg_interchange_format_length; + uint8 jpeg_proc; + uint8 subsamplingcorrect; + uint8 subsamplingcorrect_done; + uint8 subsampling_tag; + uint8 subsampling_hor; + uint8 subsampling_ver; + uint8 subsampling_force_desubsampling_inside_decompression; + uint8 qtable_offset_count; + uint8 dctable_offset_count; + uint8 actable_offset_count; + toff_t qtable_offset[3]; + toff_t dctable_offset[3]; + toff_t actable_offset[3]; + uint8* qtable[4]; + uint8* dctable[4]; + uint8* actable[4]; + uint16 restart_interval; + uint8 restart_index; + uint8 sof_log; + uint8 sof_marker_id; + uint32 sof_x; + uint32 sof_y; + uint8 sof_c[3]; + uint8 sof_hv[3]; + uint8 sof_tq[3]; + uint8 sos_cs[3]; + uint8 sos_tda[3]; + struct { + uint8 log; + OJPEGStateInBufferSource in_buffer_source; + tstrile_t in_buffer_next_strile; + toff_t in_buffer_file_pos; + toff_t in_buffer_file_togo; + } sos_end[3]; + uint8 readheader_done; + uint8 writeheader_done; + tsample_t write_cursample; + tstrile_t write_curstrile; + uint8 libjpeg_session_active; + uint8 libjpeg_jpeg_query_style; + jpeg_error_mgr libjpeg_jpeg_error_mgr; + jpeg_decompress_struct libjpeg_jpeg_decompress_struct; + jpeg_source_mgr libjpeg_jpeg_source_mgr; + uint8 subsampling_convert_log; + uint32 subsampling_convert_ylinelen; + uint32 subsampling_convert_ylines; + uint32 subsampling_convert_clinelen; + uint32 subsampling_convert_clines; + uint32 subsampling_convert_ybuflen; + uint32 subsampling_convert_cbuflen; + uint32 subsampling_convert_ycbcrbuflen; + uint8* subsampling_convert_ycbcrbuf; + uint8* subsampling_convert_ybuf; + uint8* subsampling_convert_cbbuf; + uint8* subsampling_convert_crbuf; + uint32 subsampling_convert_ycbcrimagelen; + uint8** subsampling_convert_ycbcrimage; + uint32 subsampling_convert_clinelenout; + uint32 subsampling_convert_state; + uint32 bytes_per_line; /* if the codec outputs subsampled data, a 'line' in bytes_per_line */ + uint32 lines_per_strile; /* and lines_per_strile means subsampling_ver desubsampled rows */ + OJPEGStateInBufferSource in_buffer_source; + tstrile_t in_buffer_next_strile; + tstrile_t in_buffer_strile_count; + toff_t in_buffer_file_pos; + uint8 in_buffer_file_pos_log; + toff_t in_buffer_file_togo; + uint16 in_buffer_togo; + uint8* in_buffer_cur; + uint8 in_buffer[OJPEG_BUFFER]; + OJPEGStateOutState out_state; + uint8 out_buffer[OJPEG_BUFFER]; + uint8* skip_buffer; +} OJPEGState; + +static int OJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap); +static int OJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap); +static void OJPEGPrintDir(TIFF* tif, FILE* fd, long flags); + +static int OJPEGSetupDecode(TIFF* tif); +static int OJPEGPreDecode(TIFF* tif, tsample_t s); +static int OJPEGPreDecodeSkipRaw(TIFF* tif); +static int OJPEGPreDecodeSkipScanlines(TIFF* tif); +static int OJPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s); +static int OJPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc); +static int OJPEGDecodeScanlines(TIFF* tif, tidata_t buf, tsize_t cc); +static void OJPEGPostDecode(TIFF* tif, tidata_t buf, tsize_t cc); +static int OJPEGSetupEncode(TIFF* tif); +static int OJPEGPreEncode(TIFF* tif, tsample_t s); +static int OJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s); +static int OJPEGPostEncode(TIFF* tif); +static void OJPEGCleanup(TIFF* tif); + +static void OJPEGSubsamplingCorrect(TIFF* tif); +static int OJPEGReadHeaderInfo(TIFF* tif); +static int OJPEGReadSecondarySos(TIFF* tif, tsample_t s); +static int OJPEGWriteHeaderInfo(TIFF* tif); +static void OJPEGLibjpegSessionAbort(TIFF* tif); + +static int OJPEGReadHeaderInfoSec(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamDri(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamDht(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id); +static int OJPEGReadHeaderInfoSecStreamSos(TIFF* tif); +static int OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif); +static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif); +static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif); + +static int OJPEGReadBufferFill(OJPEGState* sp); +static int OJPEGReadByte(OJPEGState* sp, uint8* byte); +static int OJPEGReadBytePeek(OJPEGState* sp, uint8* byte); +static void OJPEGReadByteAdvance(OJPEGState* sp); +static int OJPEGReadWord(OJPEGState* sp, uint16* word); +static int OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem); +static void OJPEGReadSkip(OJPEGState* sp, uint16 len); + +static int OJPEGWriteStream(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); +static void OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); +static void OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); +static void OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len); +static int OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len); + +#ifdef LIBJPEG_ENCAP_EXTERNAL +extern int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); +extern int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); +extern int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); +extern int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); +extern int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); +extern void jpeg_encap_unwind(TIFF* tif); +#else +static int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* j); +static int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); +static int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); +static int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); +static int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); +static void jpeg_encap_unwind(TIFF* tif); +#endif + +static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo); +static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo); +static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo); +static boolean OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo); +static void OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes); +static boolean OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired); +static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo); + +int +TIFFInitOJPEG(TIFF* tif, int scheme) +{ + static const char module[]="TIFFInitOJPEG"; + OJPEGState* sp; + + assert(scheme==COMPRESSION_OJPEG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif,ojpeg_field_info,FIELD_OJPEG_COUNT)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging Old JPEG codec-specific tags failed"); + return 0; + } + + /* state block */ + sp=_TIFFmalloc(sizeof(OJPEGState)); + if (sp==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"No space for OJPEG state block"); + return(0); + } + _TIFFmemset(sp,0,sizeof(OJPEGState)); + sp->tif=tif; + sp->jpeg_proc=1; + sp->subsampling_hor=2; + sp->subsampling_ver=2; + TIFFSetField(tif,TIFFTAG_YCBCRSUBSAMPLING,2,2); + /* tif codec methods */ + tif->tif_setupdecode=OJPEGSetupDecode; + tif->tif_predecode=OJPEGPreDecode; + tif->tif_postdecode=OJPEGPostDecode; + tif->tif_decoderow=OJPEGDecode; + tif->tif_decodestrip=OJPEGDecode; + tif->tif_decodetile=OJPEGDecode; + tif->tif_setupencode=OJPEGSetupEncode; + tif->tif_preencode=OJPEGPreEncode; + tif->tif_postencode=OJPEGPostEncode; + tif->tif_encoderow=OJPEGEncode; + tif->tif_encodestrip=OJPEGEncode; + tif->tif_encodetile=OJPEGEncode; + tif->tif_cleanup=OJPEGCleanup; + tif->tif_data=(tidata_t)sp; + /* tif tag methods */ + sp->vgetparent=tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield=OJPEGVGetField; + sp->vsetparent=tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield=OJPEGVSetField; + tif->tif_tagmethods.printdir=OJPEGPrintDir; + /* Some OJPEG files don't have strip or tile offsets or bytecounts tags. + Some others do, but have totally meaningless or corrupt values + in these tags. In these cases, the JpegInterchangeFormat stream is + reliable. In any case, this decoder reads the compressed data itself, + from the most reliable locations, and we need to notify encapsulating + LibTiff not to read raw strips or tiles for us. */ + tif->tif_flags|=TIFF_NOREADRAW; + return(1); +} + +static int +OJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + switch(tag) + { + case TIFFTAG_JPEGIFOFFSET: + *va_arg(ap,uint32*)=(uint32)sp->jpeg_interchange_format; + break; + case TIFFTAG_JPEGIFBYTECOUNT: + *va_arg(ap,uint32*)=(uint32)sp->jpeg_interchange_format_length; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + if (sp->subsamplingcorrect_done==0) + OJPEGSubsamplingCorrect(tif); + *va_arg(ap,uint16*)=(uint16)sp->subsampling_hor; + *va_arg(ap,uint16*)=(uint16)sp->subsampling_ver; + break; + case TIFFTAG_JPEGQTABLES: + *va_arg(ap,uint32*)=(uint32)sp->qtable_offset_count; + *va_arg(ap,void**)=(void*)sp->qtable_offset; + break; + case TIFFTAG_JPEGDCTABLES: + *va_arg(ap,uint32*)=(uint32)sp->dctable_offset_count; + *va_arg(ap,void**)=(void*)sp->dctable_offset; + break; + case TIFFTAG_JPEGACTABLES: + *va_arg(ap,uint32*)=(uint32)sp->actable_offset_count; + *va_arg(ap,void**)=(void*)sp->actable_offset; + break; + case TIFFTAG_JPEGPROC: + *va_arg(ap,uint16*)=(uint16)sp->jpeg_proc; + break; + case TIFFTAG_JPEGRESTARTINTERVAL: + *va_arg(ap,uint16*)=sp->restart_interval; + break; + default: + return (*sp->vgetparent)(tif,tag,ap); + } + return (1); +} + +static int +OJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + static const char module[]="OJPEGVSetField"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 ma; + uint32* mb; + uint32 n; + switch(tag) + { + case TIFFTAG_JPEGIFOFFSET: + sp->jpeg_interchange_format=(toff_t)va_arg(ap,uint32); + break; + case TIFFTAG_JPEGIFBYTECOUNT: + sp->jpeg_interchange_format_length=(toff_t)va_arg(ap,uint32); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + sp->subsampling_tag=1; + sp->subsampling_hor=(uint8)va_arg(ap,int); + sp->subsampling_ver=(uint8)va_arg(ap,int); + tif->tif_dir.td_ycbcrsubsampling[0]=sp->subsampling_hor; + tif->tif_dir.td_ycbcrsubsampling[1]=sp->subsampling_ver; + break; + case TIFFTAG_JPEGQTABLES: + ma=va_arg(ap,uint32); + if (ma!=0) + { + if (ma>3) + { + TIFFErrorExt(tif->tif_clientdata,module,"JpegQTables tag has incorrect count"); + return(0); + } + sp->qtable_offset_count=(uint8)ma; + mb=va_arg(ap,uint32*); + for (n=0; nqtable_offset[n]=(toff_t)mb[n]; + } + break; + case TIFFTAG_JPEGDCTABLES: + ma=va_arg(ap,uint32); + if (ma!=0) + { + if (ma>3) + { + TIFFErrorExt(tif->tif_clientdata,module,"JpegDcTables tag has incorrect count"); + return(0); + } + sp->dctable_offset_count=(uint8)ma; + mb=va_arg(ap,uint32*); + for (n=0; ndctable_offset[n]=(toff_t)mb[n]; + } + break; + case TIFFTAG_JPEGACTABLES: + ma=va_arg(ap,uint32); + if (ma!=0) + { + if (ma>3) + { + TIFFErrorExt(tif->tif_clientdata,module,"JpegAcTables tag has incorrect count"); + return(0); + } + sp->actable_offset_count=(uint8)ma; + mb=va_arg(ap,uint32*); + for (n=0; nactable_offset[n]=(toff_t)mb[n]; + } + break; + case TIFFTAG_JPEGPROC: + sp->jpeg_proc=(uint8)va_arg(ap,uint32); + break; + case TIFFTAG_JPEGRESTARTINTERVAL: + sp->restart_interval=(uint16)va_arg(ap,uint32); + break; + default: + return (*sp->vsetparent)(tif,tag,ap); + } + TIFFSetFieldBit(tif,_TIFFFieldWithTag(tif,tag)->field_bit); + tif->tif_flags|=TIFF_DIRTYDIRECT; + return(1); +} + +static void +OJPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + (void)flags; + assert(sp!=NULL); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMAT)) + fprintf(fd," JpegInterchangeFormat: %lu\n",(unsigned long)sp->jpeg_interchange_format); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH)) + fprintf(fd," JpegInterchangeFormatLength: %lu\n",(unsigned long)sp->jpeg_interchange_format_length); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGQTABLES)) + { + fprintf(fd," JpegQTables:"); + for (m=0; mqtable_offset_count; m++) + fprintf(fd," %lu",(unsigned long)sp->qtable_offset[m]); + fprintf(fd,"\n"); + } + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGDCTABLES)) + { + fprintf(fd," JpegDcTables:"); + for (m=0; mdctable_offset_count; m++) + fprintf(fd," %lu",(unsigned long)sp->dctable_offset[m]); + fprintf(fd,"\n"); + } + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGACTABLES)) + { + fprintf(fd," JpegAcTables:"); + for (m=0; mactable_offset_count; m++) + fprintf(fd," %lu",(unsigned long)sp->actable_offset[m]); + fprintf(fd,"\n"); + } + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGPROC)) + fprintf(fd," JpegProc: %u\n",(unsigned int)sp->jpeg_proc); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGRESTARTINTERVAL)) + fprintf(fd," JpegRestartInterval: %u\n",(unsigned int)sp->restart_interval); +} + +static int +OJPEGSetupDecode(TIFF* tif) +{ + static const char module[]="OJPEGSetupDecode"; + TIFFWarningExt(tif->tif_clientdata,module,"Depreciated and troublesome old-style JPEG compression mode, please convert to new-style JPEG compression and notify vendor of writing software"); + return(1); +} + +static int +OJPEGPreDecode(TIFF* tif, tsample_t s) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + tstrile_t m; + if (sp->subsamplingcorrect_done==0) + OJPEGSubsamplingCorrect(tif); + if (sp->readheader_done==0) + { + if (OJPEGReadHeaderInfo(tif)==0) + return(0); + } + if (sp->sos_end[s].log==0) + { + if (OJPEGReadSecondarySos(tif,s)==0) + return(0); + } + if isTiled(tif) + m=(tstrile_t)tif->tif_curtile; + else + m=(tstrile_t)tif->tif_curstrip; + if ((sp->writeheader_done!=0) && ((sp->write_cursample!=s) || (sp->write_curstrile>m))) + { + if (sp->libjpeg_session_active!=0) + OJPEGLibjpegSessionAbort(tif); + sp->writeheader_done=0; + } + if (sp->writeheader_done==0) + { + sp->plane_sample_offset=s; + sp->write_cursample=s; + sp->write_curstrile=s*tif->tif_dir.td_stripsperimage; + if ((sp->in_buffer_file_pos_log==0) || + (sp->in_buffer_file_pos-sp->in_buffer_togo!=sp->sos_end[s].in_buffer_file_pos)) + { + sp->in_buffer_source=sp->sos_end[s].in_buffer_source; + sp->in_buffer_next_strile=sp->sos_end[s].in_buffer_next_strile; + sp->in_buffer_file_pos=sp->sos_end[s].in_buffer_file_pos; + sp->in_buffer_file_pos_log=0; + sp->in_buffer_file_togo=sp->sos_end[s].in_buffer_file_togo; + sp->in_buffer_togo=0; + sp->in_buffer_cur=0; + } + if (OJPEGWriteHeaderInfo(tif)==0) + return(0); + } + while (sp->write_curstrilelibjpeg_jpeg_query_style==0) + { + if (OJPEGPreDecodeSkipRaw(tif)==0) + return(0); + } + else + { + if (OJPEGPreDecodeSkipScanlines(tif)==0) + return(0); + } + sp->write_curstrile++; + } + return(1); +} + +static int +OJPEGPreDecodeSkipRaw(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 m; + m=sp->lines_per_strile; + if (sp->subsampling_convert_state!=0) + { + if (sp->subsampling_convert_clines-sp->subsampling_convert_state>=m) + { + sp->subsampling_convert_state+=m; + if (sp->subsampling_convert_state==sp->subsampling_convert_clines) + sp->subsampling_convert_state=0; + return(1); + } + m-=sp->subsampling_convert_clines-sp->subsampling_convert_state; + sp->subsampling_convert_state=0; + } + while (m>=sp->subsampling_convert_clines) + { + if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) + return(0); + m-=sp->subsampling_convert_clines; + } + if (m>0) + { + if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) + return(0); + sp->subsampling_convert_state=m; + } + return(1); +} + +static int +OJPEGPreDecodeSkipScanlines(TIFF* tif) +{ + static const char module[]="OJPEGPreDecodeSkipScanlines"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 m; + if (sp->skip_buffer==NULL) + { + sp->skip_buffer=_TIFFmalloc(sp->bytes_per_line); + if (sp->skip_buffer==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + } + for (m=0; mlines_per_strile; m++) + { + if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&sp->skip_buffer,1)==0) + return(0); + } + return(1); +} + +static int +OJPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + (void)s; + if (sp->libjpeg_jpeg_query_style==0) + { + if (OJPEGDecodeRaw(tif,buf,cc)==0) + return(0); + } + else + { + if (OJPEGDecodeScanlines(tif,buf,cc)==0) + return(0); + } + return(1); +} + +static int +OJPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc) +{ + static const char module[]="OJPEGDecodeRaw"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8* m; + uint32 n; + uint8* oy; + uint8* ocb; + uint8* ocr; + uint8* p; + uint32 q; + uint8* r; + uint8 sx,sy; + if (cc%sp->bytes_per_line!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); + return(0); + } + assert(cc>0); + m=buf; + n=cc; + do + { + if (sp->subsampling_convert_state==0) + { + if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) + return(0); + } + oy=sp->subsampling_convert_ybuf+sp->subsampling_convert_state*sp->subsampling_ver*sp->subsampling_convert_ylinelen; + ocb=sp->subsampling_convert_cbbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; + ocr=sp->subsampling_convert_crbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; + p=m; + for (q=0; qsubsampling_convert_clinelenout; q++) + { + r=oy; + for (sy=0; sysubsampling_ver; sy++) + { + for (sx=0; sxsubsampling_hor; sx++) + *p++=*r++; + r+=sp->subsampling_convert_ylinelen-sp->subsampling_hor; + } + oy+=sp->subsampling_hor; + *p++=*ocb++; + *p++=*ocr++; + } + sp->subsampling_convert_state++; + if (sp->subsampling_convert_state==sp->subsampling_convert_clines) + sp->subsampling_convert_state=0; + m+=sp->bytes_per_line; + n-=sp->bytes_per_line; + } while(n>0); + return(1); +} + +static int +OJPEGDecodeScanlines(TIFF* tif, tidata_t buf, tsize_t cc) +{ + static const char module[]="OJPEGDecodeScanlines"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8* m; + uint32 n; + if (cc%sp->bytes_per_line!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); + return(0); + } + assert(cc>0); + m=buf; + n=cc; + do + { + if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&m,1)==0) + return(0); + m+=sp->bytes_per_line; + n-=sp->bytes_per_line; + } while(n>0); + return(1); +} + +static void +OJPEGPostDecode(TIFF* tif, tidata_t buf, tsize_t cc) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + (void)buf; + (void)cc; + sp->write_curstrile++; + if (sp->write_curstrile%tif->tif_dir.td_stripsperimage==0) + { + assert(sp->libjpeg_session_active!=0); + OJPEGLibjpegSessionAbort(tif); + sp->writeheader_done=0; + } +} + +static int +OJPEGSetupEncode(TIFF* tif) +{ + static const char module[]="OJPEGSetupEncode"; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static int +OJPEGPreEncode(TIFF* tif, tsample_t s) +{ + static const char module[]="OJPEGPreEncode"; + (void)s; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static int +OJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + static const char module[]="OJPEGEncode"; + (void)buf; + (void)cc; + (void)s; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static int +OJPEGPostEncode(TIFF* tif) +{ + static const char module[]="OJPEGPostEncode"; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static void +OJPEGCleanup(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp!=0) + { + tif->tif_tagmethods.vgetfield=sp->vgetparent; + tif->tif_tagmethods.vsetfield=sp->vsetparent; + if (sp->qtable[0]!=0) + _TIFFfree(sp->qtable[0]); + if (sp->qtable[1]!=0) + _TIFFfree(sp->qtable[1]); + if (sp->qtable[2]!=0) + _TIFFfree(sp->qtable[2]); + if (sp->qtable[3]!=0) + _TIFFfree(sp->qtable[3]); + if (sp->dctable[0]!=0) + _TIFFfree(sp->dctable[0]); + if (sp->dctable[1]!=0) + _TIFFfree(sp->dctable[1]); + if (sp->dctable[2]!=0) + _TIFFfree(sp->dctable[2]); + if (sp->dctable[3]!=0) + _TIFFfree(sp->dctable[3]); + if (sp->actable[0]!=0) + _TIFFfree(sp->actable[0]); + if (sp->actable[1]!=0) + _TIFFfree(sp->actable[1]); + if (sp->actable[2]!=0) + _TIFFfree(sp->actable[2]); + if (sp->actable[3]!=0) + _TIFFfree(sp->actable[3]); + if (sp->libjpeg_session_active!=0) + OJPEGLibjpegSessionAbort(tif); + if (sp->subsampling_convert_ycbcrbuf!=0) + _TIFFfree(sp->subsampling_convert_ycbcrbuf); + if (sp->subsampling_convert_ycbcrimage!=0) + _TIFFfree(sp->subsampling_convert_ycbcrimage); + if (sp->skip_buffer!=0) + _TIFFfree(sp->skip_buffer); + _TIFFfree(sp); + tif->tif_data=NULL; + _TIFFSetDefaultCompressionState(tif); + } +} + +static void +OJPEGSubsamplingCorrect(TIFF* tif) +{ + static const char module[]="OJPEGSubsamplingCorrect"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 mh; + uint8 mv; + assert(sp->subsamplingcorrect_done==0); + if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) && + (tif->tif_dir.td_photometric!=PHOTOMETRIC_ITULAB))) + { + if (sp->subsampling_tag!=0) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag not appropriate for this Photometric and/or SamplesPerPixel"); + sp->subsampling_hor=1; + sp->subsampling_ver=1; + sp->subsampling_force_desubsampling_inside_decompression=0; + } + else + { + sp->subsamplingcorrect_done=1; + mh=sp->subsampling_hor; + mv=sp->subsampling_ver; + sp->subsamplingcorrect=1; + OJPEGReadHeaderInfoSec(tif); + if (sp->subsampling_force_desubsampling_inside_decompression!=0) + { + sp->subsampling_hor=1; + sp->subsampling_ver=1; + } + sp->subsamplingcorrect=0; + if (((sp->subsampling_hor!=mh) || (sp->subsampling_ver!=mv)) && (sp->subsampling_force_desubsampling_inside_decompression==0)) + { + if (sp->subsampling_tag==0) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data [%d,%d] does not match default values [2,2]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver); + else + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data [%d,%d] does not match subsampling tag values [%d,%d]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver,mh,mv); + } + if (sp->subsampling_force_desubsampling_inside_decompression!=0) + { + if (sp->subsampling_tag==0) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression"); + else + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data does not match subsampling tag values [%d,%d] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression",mh,mv); + } + if (sp->subsampling_force_desubsampling_inside_decompression==0) + { + if (sp->subsampling_horsubsampling_ver) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling values [%d,%d] are not allowed in TIFF",sp->subsampling_hor,sp->subsampling_ver); + } + } + sp->subsamplingcorrect_done=1; +} + +static int +OJPEGReadHeaderInfo(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfo"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(sp->readheader_done==0); + sp->image_width=tif->tif_dir.td_imagewidth; + sp->image_length=tif->tif_dir.td_imagelength; + if isTiled(tif) + { + sp->strile_width=tif->tif_dir.td_tilewidth; + sp->strile_length=tif->tif_dir.td_tilelength; + sp->strile_length_total=((sp->image_length+sp->strile_length-1)/sp->strile_length)*sp->strile_length; + } + else + { + sp->strile_width=sp->image_width; + sp->strile_length=tif->tif_dir.td_rowsperstrip; + sp->strile_length_total=sp->image_length; + } + sp->samples_per_pixel=tif->tif_dir.td_samplesperpixel; + if (sp->samples_per_pixel==1) + { + sp->plane_sample_offset=0; + sp->samples_per_pixel_per_plane=sp->samples_per_pixel; + sp->subsampling_hor=1; + sp->subsampling_ver=1; + } + else + { + if (sp->samples_per_pixel!=3) + { + TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d not supported for this compression scheme",sp->samples_per_pixel); + return(0); + } + sp->plane_sample_offset=0; + if (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG) + sp->samples_per_pixel_per_plane=3; + else + sp->samples_per_pixel_per_plane=1; + } + if (sp->strile_lengthimage_length) + { + if (sp->strile_length%(sp->subsampling_ver*8)!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Incompatible vertical subsampling and image strip/tile length"); + return(0); + } + sp->restart_interval=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8))*(sp->strile_length/(sp->subsampling_ver*8)); + } + if (OJPEGReadHeaderInfoSec(tif)==0) + return(0); + sp->sos_end[0].log=1; + sp->sos_end[0].in_buffer_source=sp->in_buffer_source; + sp->sos_end[0].in_buffer_next_strile=sp->in_buffer_next_strile; + sp->sos_end[0].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; + sp->sos_end[0].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; + sp->readheader_done=1; + return(1); +} + +static int +OJPEGReadSecondarySos(TIFF* tif, tsample_t s) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + assert(s>0); + assert(s<3); + assert(sp->sos_end[0].log!=0); + assert(sp->sos_end[s].log==0); + sp->plane_sample_offset=s-1; + while(sp->sos_end[sp->plane_sample_offset].log==0) + sp->plane_sample_offset--; + sp->in_buffer_source=sp->sos_end[sp->plane_sample_offset].in_buffer_source; + sp->in_buffer_next_strile=sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile; + sp->in_buffer_file_pos=sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos; + sp->in_buffer_file_pos_log=0; + sp->in_buffer_file_togo=sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo; + sp->in_buffer_togo=0; + sp->in_buffer_cur=0; + while(sp->plane_sample_offsetplane_sample_offset++; + if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) + return(0); + sp->sos_end[sp->plane_sample_offset].log=1; + sp->sos_end[sp->plane_sample_offset].in_buffer_source=sp->in_buffer_source; + sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile=sp->in_buffer_next_strile; + sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; + sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; + } + return(1); +} + +static int +OJPEGWriteHeaderInfo(TIFF* tif) +{ + static const char module[]="OJPEGWriteHeaderInfo"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8** m; + uint32 n; + assert(sp->libjpeg_session_active==0); + sp->out_state=ososSoi; + sp->restart_index=0; + jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr)); + sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage; + sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit; + sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr); + sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif; + if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) + return(0); + sp->libjpeg_session_active=1; + sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=0; + sp->libjpeg_jpeg_source_mgr.init_source=OJPEGLibjpegJpegSourceMgrInitSource; + sp->libjpeg_jpeg_source_mgr.fill_input_buffer=OJPEGLibjpegJpegSourceMgrFillInputBuffer; + sp->libjpeg_jpeg_source_mgr.skip_input_data=OJPEGLibjpegJpegSourceMgrSkipInputData; + sp->libjpeg_jpeg_source_mgr.resync_to_restart=OJPEGLibjpegJpegSourceMgrResyncToRestart; + sp->libjpeg_jpeg_source_mgr.term_source=OJPEGLibjpegJpegSourceMgrTermSource; + sp->libjpeg_jpeg_decompress_struct.src=&(sp->libjpeg_jpeg_source_mgr); + if (jpeg_read_header_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),1)==0) + return(0); + if ((sp->subsampling_force_desubsampling_inside_decompression==0) && (sp->samples_per_pixel_per_plane>1)) + { + sp->libjpeg_jpeg_decompress_struct.raw_data_out=1; +#if JPEG_LIB_VERSION >= 70 + sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling=FALSE; +#endif + sp->libjpeg_jpeg_query_style=0; + if (sp->subsampling_convert_log==0) + { + assert(sp->subsampling_convert_ycbcrbuf==0); + assert(sp->subsampling_convert_ycbcrimage==0); + sp->subsampling_convert_ylinelen=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8)*sp->subsampling_hor*8); + sp->subsampling_convert_ylines=sp->subsampling_ver*8; + sp->subsampling_convert_clinelen=sp->subsampling_convert_ylinelen/sp->subsampling_hor; + sp->subsampling_convert_clines=8; + sp->subsampling_convert_ybuflen=sp->subsampling_convert_ylinelen*sp->subsampling_convert_ylines; + sp->subsampling_convert_cbuflen=sp->subsampling_convert_clinelen*sp->subsampling_convert_clines; + sp->subsampling_convert_ycbcrbuflen=sp->subsampling_convert_ybuflen+2*sp->subsampling_convert_cbuflen; + sp->subsampling_convert_ycbcrbuf=_TIFFmalloc(sp->subsampling_convert_ycbcrbuflen); + if (sp->subsampling_convert_ycbcrbuf==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + sp->subsampling_convert_ybuf=sp->subsampling_convert_ycbcrbuf; + sp->subsampling_convert_cbbuf=sp->subsampling_convert_ybuf+sp->subsampling_convert_ybuflen; + sp->subsampling_convert_crbuf=sp->subsampling_convert_cbbuf+sp->subsampling_convert_cbuflen; + sp->subsampling_convert_ycbcrimagelen=3+sp->subsampling_convert_ylines+2*sp->subsampling_convert_clines; + sp->subsampling_convert_ycbcrimage=_TIFFmalloc(sp->subsampling_convert_ycbcrimagelen*sizeof(uint8*)); + if (sp->subsampling_convert_ycbcrimage==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + m=sp->subsampling_convert_ycbcrimage; + *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3); + *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines); + *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines+sp->subsampling_convert_clines); + for (n=0; nsubsampling_convert_ylines; n++) + *m++=sp->subsampling_convert_ybuf+n*sp->subsampling_convert_ylinelen; + for (n=0; nsubsampling_convert_clines; n++) + *m++=sp->subsampling_convert_cbbuf+n*sp->subsampling_convert_clinelen; + for (n=0; nsubsampling_convert_clines; n++) + *m++=sp->subsampling_convert_crbuf+n*sp->subsampling_convert_clinelen; + sp->subsampling_convert_clinelenout=((sp->strile_width+sp->subsampling_hor-1)/sp->subsampling_hor); + sp->subsampling_convert_state=0; + sp->bytes_per_line=sp->subsampling_convert_clinelenout*(sp->subsampling_ver*sp->subsampling_hor+2); + sp->lines_per_strile=((sp->strile_length+sp->subsampling_ver-1)/sp->subsampling_ver); + sp->subsampling_convert_log=1; + } + } + else + { + sp->libjpeg_jpeg_decompress_struct.jpeg_color_space=JCS_UNKNOWN; + sp->libjpeg_jpeg_decompress_struct.out_color_space=JCS_UNKNOWN; + sp->libjpeg_jpeg_query_style=1; + sp->bytes_per_line=sp->samples_per_pixel_per_plane*sp->strile_width; + sp->lines_per_strile=sp->strile_length; + } + if (jpeg_start_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) + return(0); + sp->writeheader_done=1; + return(1); +} + +static void +OJPEGLibjpegSessionAbort(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(sp->libjpeg_session_active!=0); + jpeg_destroy((jpeg_common_struct*)(&(sp->libjpeg_jpeg_decompress_struct))); + sp->libjpeg_session_active=0; +} + +static int +OJPEGReadHeaderInfoSec(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSec"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint16 n; + uint8 o; + if (sp->file_size==0) + sp->file_size=TIFFGetFileSize(tif); + if (sp->jpeg_interchange_format!=0) + { + if (sp->jpeg_interchange_format>=sp->file_size) + { + sp->jpeg_interchange_format=0; + sp->jpeg_interchange_format_length=0; + } + else + { + if ((sp->jpeg_interchange_format_length==0) || (sp->jpeg_interchange_format+sp->jpeg_interchange_format_length>sp->file_size)) + sp->jpeg_interchange_format_length=sp->file_size-sp->jpeg_interchange_format; + } + } + sp->in_buffer_source=osibsNotSetYet; + sp->in_buffer_next_strile=0; + sp->in_buffer_strile_count=tif->tif_dir.td_nstrips; + sp->in_buffer_file_togo=0; + sp->in_buffer_togo=0; + do + { + if (OJPEGReadBytePeek(sp,&m)==0) + return(0); + if (m!=255) + break; + OJPEGReadByteAdvance(sp); + do + { + if (OJPEGReadByte(sp,&m)==0) + return(0); + } while(m==255); + switch(m) + { + case JPEG_MARKER_SOI: + /* this type of marker has no data, and should be skipped */ + break; + case JPEG_MARKER_COM: + case JPEG_MARKER_APP0: + case JPEG_MARKER_APP0+1: + case JPEG_MARKER_APP0+2: + case JPEG_MARKER_APP0+3: + case JPEG_MARKER_APP0+4: + case JPEG_MARKER_APP0+5: + case JPEG_MARKER_APP0+6: + case JPEG_MARKER_APP0+7: + case JPEG_MARKER_APP0+8: + case JPEG_MARKER_APP0+9: + case JPEG_MARKER_APP0+10: + case JPEG_MARKER_APP0+11: + case JPEG_MARKER_APP0+12: + case JPEG_MARKER_APP0+13: + case JPEG_MARKER_APP0+14: + case JPEG_MARKER_APP0+15: + /* this type of marker has data, but it has no use to us (and no place here) and should be skipped */ + if (OJPEGReadWord(sp,&n)==0) + return(0); + if (n<2) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); + return(0); + } + if (n>2) + OJPEGReadSkip(sp,n-2); + break; + case JPEG_MARKER_DRI: + if (OJPEGReadHeaderInfoSecStreamDri(tif)==0) + return(0); + break; + case JPEG_MARKER_DQT: + if (OJPEGReadHeaderInfoSecStreamDqt(tif)==0) + return(0); + break; + case JPEG_MARKER_DHT: + if (OJPEGReadHeaderInfoSecStreamDht(tif)==0) + return(0); + break; + case JPEG_MARKER_SOF0: + case JPEG_MARKER_SOF1: + case JPEG_MARKER_SOF3: + if (OJPEGReadHeaderInfoSecStreamSof(tif,m)==0) + return(0); + if (sp->subsamplingcorrect!=0) + return(1); + break; + case JPEG_MARKER_SOS: + if (sp->subsamplingcorrect!=0) + return(1); + assert(sp->plane_sample_offset==0); + if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) + return(0); + break; + default: + TIFFErrorExt(tif->tif_clientdata,module,"Unknown marker type %d in JPEG data",m); + return(0); + } + } while(m!=JPEG_MARKER_SOS); + if (sp->subsamplingcorrect) + return(1); + if (sp->sof_log==0) + { + if (OJPEGReadHeaderInfoSecTablesQTable(tif)==0) + return(0); + sp->sof_marker_id=JPEG_MARKER_SOF0; + for (o=0; osamples_per_pixel; o++) + sp->sof_c[o]=o; + sp->sof_hv[0]=((sp->subsampling_hor<<4)|sp->subsampling_ver); + for (o=1; osamples_per_pixel; o++) + sp->sof_hv[o]=17; + sp->sof_x=sp->strile_width; + sp->sof_y=sp->strile_length_total; + sp->sof_log=1; + if (OJPEGReadHeaderInfoSecTablesDcTable(tif)==0) + return(0); + if (OJPEGReadHeaderInfoSecTablesAcTable(tif)==0) + return(0); + for (o=1; osamples_per_pixel; o++) + sp->sos_cs[o]=o; + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamDri(TIFF* tif) +{ + /* this could easilly cause trouble in some cases... but no such cases have occured sofar */ + static const char module[]="OJPEGReadHeaderInfoSecStreamDri"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m!=4) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DRI marker in JPEG data"); + return(0); + } + if (OJPEGReadWord(sp,&m)==0) + return(0); + sp->restart_interval=m; + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif) +{ + /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ + static const char module[]="OJPEGReadHeaderInfoSecStreamDqt"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint32 na; + uint8* nb; + uint8 o; + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m<=2) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); + return(0); + } + if (sp->subsamplingcorrect!=0) + OJPEGReadSkip(sp,m-2); + else + { + m-=2; + do + { + if (m<65) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); + return(0); + } + na=sizeof(uint32)+69; + nb=_TIFFmalloc(na); + if (nb==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)nb=na; + nb[sizeof(uint32)]=255; + nb[sizeof(uint32)+1]=JPEG_MARKER_DQT; + nb[sizeof(uint32)+2]=0; + nb[sizeof(uint32)+3]=67; + if (OJPEGReadBlock(sp,65,&nb[sizeof(uint32)+4])==0) + return(0); + o=nb[sizeof(uint32)+4]&15; + if (3tif_clientdata,module,"Corrupt DQT marker in JPEG data"); + return(0); + } + if (sp->qtable[o]!=0) + _TIFFfree(sp->qtable[o]); + sp->qtable[o]=nb; + m-=65; + } while(m>0); + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamDht(TIFF* tif) +{ + /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ + /* TODO: the following assumes there is only one table in this marker... but i'm not quite sure that assumption is guaranteed correct */ + static const char module[]="OJPEGReadHeaderInfoSecStreamDht"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint32 na; + uint8* nb; + uint8 o; + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m<=2) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + if (sp->subsamplingcorrect!=0) + { + OJPEGReadSkip(sp,m-2); + } + else + { + na=sizeof(uint32)+2+m; + nb=_TIFFmalloc(na); + if (nb==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)nb=na; + nb[sizeof(uint32)]=255; + nb[sizeof(uint32)+1]=JPEG_MARKER_DHT; + nb[sizeof(uint32)+2]=(m>>8); + nb[sizeof(uint32)+3]=(m&255); + if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0) + return(0); + o=nb[sizeof(uint32)+4]; + if ((o&240)==0) + { + if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + if (sp->dctable[o]!=0) + _TIFFfree(sp->dctable[o]); + sp->dctable[o]=nb; + } + else + { + if ((o&240)!=16) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + o&=15; + if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + if (sp->actable[o]!=0) + _TIFFfree(sp->actable[o]); + sp->actable[o]=nb; + } + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id) +{ + /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ + static const char module[]="OJPEGReadHeaderInfoSecStreamSof"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint16 n; + uint8 o; + uint16 p; + uint16 q; + if (sp->sof_log!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); + return(0); + } + if (sp->subsamplingcorrect==0) + sp->sof_marker_id=marker_id; + /* Lf: data length */ + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m<11) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); + return(0); + } + m-=8; + if (m%3!=0) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); + return(0); + } + n=m/3; + if (sp->subsamplingcorrect==0) + { + if (n!=sp->samples_per_pixel) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of samples"); + return(0); + } + } + /* P: Sample precision */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (o!=8) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of bits per sample"); + return(0); + } + /* Y: Number of lines, X: Number of samples per line */ + if (sp->subsamplingcorrect) + OJPEGReadSkip(sp,4); + else + { + /* TODO: probably best to also add check on allowed upper bound, especially x, may cause buffer overflow otherwise i think */ + /* Y: Number of lines */ + if (OJPEGReadWord(sp,&p)==0) + return(0); + if ((pimage_length) && (pstrile_length_total)) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected height"); + return(0); + } + sp->sof_y=p; + /* X: Number of samples per line */ + if (OJPEGReadWord(sp,&p)==0) + return(0); + if ((pimage_width) && (pstrile_width)) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width"); + return(0); + } + sp->sof_x=p; + } + /* Nf: Number of image components in frame */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (o!=n) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); + return(0); + } + /* per component stuff */ + /* TODO: double-check that flow implies that n cannot be as big as to make us overflow sof_c, sof_hv and sof_tq arrays */ + for (q=0; qsubsamplingcorrect==0) + sp->sof_c[q]=o; + /* H: Horizontal sampling factor, and V: Vertical sampling factor */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (sp->subsamplingcorrect!=0) + { + if (q==0) + { + sp->subsampling_hor=(o>>4); + sp->subsampling_ver=(o&15); + if (((sp->subsampling_hor!=1) && (sp->subsampling_hor!=2) && (sp->subsampling_hor!=4)) || + ((sp->subsampling_ver!=1) && (sp->subsampling_ver!=2) && (sp->subsampling_ver!=4))) + sp->subsampling_force_desubsampling_inside_decompression=1; + } + else + { + if (o!=17) + sp->subsampling_force_desubsampling_inside_decompression=1; + } + } + else + { + sp->sof_hv[q]=o; + if (sp->subsampling_force_desubsampling_inside_decompression==0) + { + if (q==0) + { + if (o!=((sp->subsampling_hor<<4)|sp->subsampling_ver)) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); + return(0); + } + } + else + { + if (o!=17) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); + return(0); + } + } + } + } + /* Tq: Quantization table destination selector */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (sp->subsamplingcorrect==0) + sp->sof_tq[q]=o; + } + if (sp->subsamplingcorrect==0) + sp->sof_log=1; + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamSos(TIFF* tif) +{ + /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ + static const char module[]="OJPEGReadHeaderInfoSecStreamSos"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint8 n; + uint8 o; + assert(sp->subsamplingcorrect==0); + if (sp->sof_log==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); + return(0); + } + /* Ls */ + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m!=6+sp->samples_per_pixel_per_plane*2) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); + return(0); + } + /* Ns */ + if (OJPEGReadByte(sp,&n)==0) + return(0); + if (n!=sp->samples_per_pixel_per_plane) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); + return(0); + } + /* Cs, Td, and Ta */ + for (o=0; osamples_per_pixel_per_plane; o++) + { + /* Cs */ + if (OJPEGReadByte(sp,&n)==0) + return(0); + sp->sos_cs[sp->plane_sample_offset+o]=n; + /* Td and Ta */ + if (OJPEGReadByte(sp,&n)==0) + return(0); + sp->sos_tda[sp->plane_sample_offset+o]=n; + } + /* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as per LibJpeg source */ + OJPEGReadSkip(sp,3); + return(1); +} + +static int +OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSecTablesQTable"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint8 n; + uint32 oa; + uint8* ob; + uint32 p; + if (sp->qtable_offset[0]==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); + return(0); + } + sp->in_buffer_file_pos_log=0; + for (m=0; msamples_per_pixel; m++) + { + if ((sp->qtable_offset[m]!=0) && ((m==0) || (sp->qtable_offset[m]!=sp->qtable_offset[m-1]))) + { + for (n=0; nqtable_offset[m]==sp->qtable_offset[n]) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegQTables tag value"); + return(0); + } + } + oa=sizeof(uint32)+69; + ob=_TIFFmalloc(oa); + if (ob==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)ob=oa; + ob[sizeof(uint32)]=255; + ob[sizeof(uint32)+1]=JPEG_MARKER_DQT; + ob[sizeof(uint32)+2]=0; + ob[sizeof(uint32)+3]=67; + ob[sizeof(uint32)+4]=m; + TIFFSeekFile(tif,sp->qtable_offset[m],SEEK_SET); + p=TIFFReadFile(tif,&ob[sizeof(uint32)+5],64); + if (p!=64) + return(0); + sp->qtable[m]=ob; + sp->sof_tq[m]=m; + } + else + sp->sof_tq[m]=sp->sof_tq[m-1]; + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSecTablesDcTable"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint8 n; + uint8 o[16]; + uint32 p; + uint32 q; + uint32 ra; + uint8* rb; + if (sp->dctable_offset[0]==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); + return(0); + } + sp->in_buffer_file_pos_log=0; + for (m=0; msamples_per_pixel; m++) + { + if ((sp->dctable_offset[m]!=0) && ((m==0) || (sp->dctable_offset[m]!=sp->dctable_offset[m-1]))) + { + for (n=0; ndctable_offset[m]==sp->dctable_offset[n]) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegDcTables tag value"); + return(0); + } + } + TIFFSeekFile(tif,sp->dctable_offset[m],SEEK_SET); + p=TIFFReadFile(tif,o,16); + if (p!=16) + return(0); + q=0; + for (n=0; n<16; n++) + q+=o[n]; + ra=sizeof(uint32)+21+q; + rb=_TIFFmalloc(ra); + if (rb==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)rb=ra; + rb[sizeof(uint32)]=255; + rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; + rb[sizeof(uint32)+2]=((19+q)>>8); + rb[sizeof(uint32)+3]=((19+q)&255); + rb[sizeof(uint32)+4]=m; + for (n=0; n<16; n++) + rb[sizeof(uint32)+5+n]=o[n]; + p=TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); + if (p!=q) + return(0); + sp->dctable[m]=rb; + sp->sos_tda[m]=(m<<4); + } + else + sp->sos_tda[m]=sp->sos_tda[m-1]; + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSecTablesAcTable"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint8 n; + uint8 o[16]; + uint32 p; + uint32 q; + uint32 ra; + uint8* rb; + if (sp->actable_offset[0]==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); + return(0); + } + sp->in_buffer_file_pos_log=0; + for (m=0; msamples_per_pixel; m++) + { + if ((sp->actable_offset[m]!=0) && ((m==0) || (sp->actable_offset[m]!=sp->actable_offset[m-1]))) + { + for (n=0; nactable_offset[m]==sp->actable_offset[n]) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegAcTables tag value"); + return(0); + } + } + TIFFSeekFile(tif,sp->actable_offset[m],SEEK_SET); + p=TIFFReadFile(tif,o,16); + if (p!=16) + return(0); + q=0; + for (n=0; n<16; n++) + q+=o[n]; + ra=sizeof(uint32)+21+q; + rb=_TIFFmalloc(ra); + if (rb==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)rb=ra; + rb[sizeof(uint32)]=255; + rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; + rb[sizeof(uint32)+2]=((19+q)>>8); + rb[sizeof(uint32)+3]=((19+q)&255); + rb[sizeof(uint32)+4]=(16|m); + for (n=0; n<16; n++) + rb[sizeof(uint32)+5+n]=o[n]; + p=TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); + if (p!=q) + return(0); + sp->actable[m]=rb; + sp->sos_tda[m]=(sp->sos_tda[m]|m); + } + else + sp->sos_tda[m]=(sp->sos_tda[m]|(sp->sos_tda[m-1]&15)); + } + return(1); +} + +static int +OJPEGReadBufferFill(OJPEGState* sp) +{ + uint16 m; + tsize_t n; + /* TODO: double-check: when subsamplingcorrect is set, no call to TIFFErrorExt or TIFFWarningExt should be made + * in any other case, seek or read errors should be passed through */ + do + { + if (sp->in_buffer_file_togo!=0) + { + if (sp->in_buffer_file_pos_log==0) + { + TIFFSeekFile(sp->tif,sp->in_buffer_file_pos,SEEK_SET); + sp->in_buffer_file_pos_log=1; + } + m=OJPEG_BUFFER; + if (m>sp->in_buffer_file_togo) + m=(uint16)sp->in_buffer_file_togo; + n=TIFFReadFile(sp->tif,sp->in_buffer,(tsize_t)m); + if (n==0) + return(0); + assert(n>0); + assert(n<=OJPEG_BUFFER); + assert(n<65536); + assert((uint16)n<=sp->in_buffer_file_togo); + m=(uint16)n; + sp->in_buffer_togo=m; + sp->in_buffer_cur=sp->in_buffer; + sp->in_buffer_file_togo-=m; + sp->in_buffer_file_pos+=m; + break; + } + sp->in_buffer_file_pos_log=0; + switch(sp->in_buffer_source) + { + case osibsNotSetYet: + if (sp->jpeg_interchange_format!=0) + { + sp->in_buffer_file_pos=sp->jpeg_interchange_format; + sp->in_buffer_file_togo=sp->jpeg_interchange_format_length; + } + sp->in_buffer_source=osibsJpegInterchangeFormat; + break; + case osibsJpegInterchangeFormat: + sp->in_buffer_source=osibsStrile; + case osibsStrile: + if (sp->in_buffer_next_strile==sp->in_buffer_strile_count) + sp->in_buffer_source=osibsEof; + else + { + if (sp->tif->tif_dir.td_stripoffset == 0) { + TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip offsets are missing"); + return(0); + } + sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile]; + if (sp->in_buffer_file_pos!=0) + { + if (sp->in_buffer_file_pos>=sp->file_size) + sp->in_buffer_file_pos=0; + else + { + sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile]; + if (sp->in_buffer_file_togo==0) + sp->in_buffer_file_pos=0; + else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size) + sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; + } + } + sp->in_buffer_next_strile++; + } + break; + default: + return(0); + } + } while (1); + return(1); +} + +static int +OJPEGReadByte(OJPEGState* sp, uint8* byte) +{ + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + *byte=*(sp->in_buffer_cur); + sp->in_buffer_cur++; + sp->in_buffer_togo--; + return(1); +} + +static int +OJPEGReadBytePeek(OJPEGState* sp, uint8* byte) +{ + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + *byte=*(sp->in_buffer_cur); + return(1); +} + +static void +OJPEGReadByteAdvance(OJPEGState* sp) +{ + assert(sp->in_buffer_togo>0); + sp->in_buffer_cur++; + sp->in_buffer_togo--; +} + +static int +OJPEGReadWord(OJPEGState* sp, uint16* word) +{ + uint8 m; + if (OJPEGReadByte(sp,&m)==0) + return(0); + *word=(m<<8); + if (OJPEGReadByte(sp,&m)==0) + return(0); + *word|=m; + return(1); +} + +static int +OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem) +{ + uint16 mlen; + uint8* mmem; + uint16 n; + assert(len>0); + mlen=len; + mmem=mem; + do + { + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + n=mlen; + if (n>sp->in_buffer_togo) + n=sp->in_buffer_togo; + _TIFFmemcpy(mmem,sp->in_buffer_cur,n); + sp->in_buffer_cur+=n; + sp->in_buffer_togo-=n; + mlen-=n; + mmem+=n; + } while(mlen>0); + return(1); +} + +static void +OJPEGReadSkip(OJPEGState* sp, uint16 len) +{ + uint16 m; + uint16 n; + m=len; + n=m; + if (n>sp->in_buffer_togo) + n=sp->in_buffer_togo; + sp->in_buffer_cur+=n; + sp->in_buffer_togo-=n; + m-=n; + if (m>0) + { + assert(sp->in_buffer_togo==0); + n=m; + if (n>sp->in_buffer_file_togo) + n=sp->in_buffer_file_togo; + sp->in_buffer_file_pos+=n; + sp->in_buffer_file_togo-=n; + sp->in_buffer_file_pos_log=0; + /* we don't skip past jpeginterchangeformat/strile block... + * if that is asked from us, we're dealing with totally bazurk + * data anyway, and we've not seen this happening on any + * testfile, so we might as well likely cause some other + * meaningless error to be passed at some later time + */ + } +} + +static int +OJPEGWriteStream(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + *len=0; + do + { + assert(sp->out_state<=ososEoi); + switch(sp->out_state) + { + case ososSoi: + OJPEGWriteStreamSoi(tif,mem,len); + break; + case ososQTable0: + OJPEGWriteStreamQTable(tif,0,mem,len); + break; + case ososQTable1: + OJPEGWriteStreamQTable(tif,1,mem,len); + break; + case ososQTable2: + OJPEGWriteStreamQTable(tif,2,mem,len); + break; + case ososQTable3: + OJPEGWriteStreamQTable(tif,3,mem,len); + break; + case ososDcTable0: + OJPEGWriteStreamDcTable(tif,0,mem,len); + break; + case ososDcTable1: + OJPEGWriteStreamDcTable(tif,1,mem,len); + break; + case ososDcTable2: + OJPEGWriteStreamDcTable(tif,2,mem,len); + break; + case ososDcTable3: + OJPEGWriteStreamDcTable(tif,3,mem,len); + break; + case ososAcTable0: + OJPEGWriteStreamAcTable(tif,0,mem,len); + break; + case ososAcTable1: + OJPEGWriteStreamAcTable(tif,1,mem,len); + break; + case ososAcTable2: + OJPEGWriteStreamAcTable(tif,2,mem,len); + break; + case ososAcTable3: + OJPEGWriteStreamAcTable(tif,3,mem,len); + break; + case ososDri: + OJPEGWriteStreamDri(tif,mem,len); + break; + case ososSof: + OJPEGWriteStreamSof(tif,mem,len); + break; + case ososSos: + OJPEGWriteStreamSos(tif,mem,len); + break; + case ososCompressed: + if (OJPEGWriteStreamCompressed(tif,mem,len)==0) + return(0); + break; + case ososRst: + OJPEGWriteStreamRst(tif,mem,len); + break; + case ososEoi: + OJPEGWriteStreamEoi(tif,mem,len); + break; + } + } while (*len==0); + return(1); +} + +static void +OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_SOI; + *len=2; + *mem=(void*)sp->out_buffer; + sp->out_state++; +} + +static void +OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->qtable[table_index]!=0) + { + *mem=(void*)(sp->qtable[table_index]+sizeof(uint32)); + *len=*((uint32*)sp->qtable[table_index])-sizeof(uint32); + } + sp->out_state++; +} + +static void +OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->dctable[table_index]!=0) + { + *mem=(void*)(sp->dctable[table_index]+sizeof(uint32)); + *len=*((uint32*)sp->dctable[table_index])-sizeof(uint32); + } + sp->out_state++; +} + +static void +OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->actable[table_index]!=0) + { + *mem=(void*)(sp->actable[table_index]+sizeof(uint32)); + *len=*((uint32*)sp->actable[table_index])-sizeof(uint32); + } + sp->out_state++; +} + +static void +OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=6); + if (sp->restart_interval!=0) + { + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_DRI; + sp->out_buffer[2]=0; + sp->out_buffer[3]=4; + sp->out_buffer[4]=(sp->restart_interval>>8); + sp->out_buffer[5]=(sp->restart_interval&255); + *len=6; + *mem=(void*)sp->out_buffer; + } + sp->out_state++; +} + +static void +OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + assert(OJPEG_BUFFER>=2+8+sp->samples_per_pixel_per_plane*3); + assert(255>=8+sp->samples_per_pixel_per_plane*3); + sp->out_buffer[0]=255; + sp->out_buffer[1]=sp->sof_marker_id; + /* Lf */ + sp->out_buffer[2]=0; + sp->out_buffer[3]=8+sp->samples_per_pixel_per_plane*3; + /* P */ + sp->out_buffer[4]=8; + /* Y */ + sp->out_buffer[5]=(sp->sof_y>>8); + sp->out_buffer[6]=(sp->sof_y&255); + /* X */ + sp->out_buffer[7]=(sp->sof_x>>8); + sp->out_buffer[8]=(sp->sof_x&255); + /* Nf */ + sp->out_buffer[9]=sp->samples_per_pixel_per_plane; + for (m=0; msamples_per_pixel_per_plane; m++) + { + /* C */ + sp->out_buffer[10+m*3]=sp->sof_c[sp->plane_sample_offset+m]; + /* H and V */ + sp->out_buffer[10+m*3+1]=sp->sof_hv[sp->plane_sample_offset+m]; + /* Tq */ + sp->out_buffer[10+m*3+2]=sp->sof_tq[sp->plane_sample_offset+m]; + } + *len=10+sp->samples_per_pixel_per_plane*3; + *mem=(void*)sp->out_buffer; + sp->out_state++; +} + +static void +OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + assert(OJPEG_BUFFER>=2+6+sp->samples_per_pixel_per_plane*2); + assert(255>=6+sp->samples_per_pixel_per_plane*2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_SOS; + /* Ls */ + sp->out_buffer[2]=0; + sp->out_buffer[3]=6+sp->samples_per_pixel_per_plane*2; + /* Ns */ + sp->out_buffer[4]=sp->samples_per_pixel_per_plane; + for (m=0; msamples_per_pixel_per_plane; m++) + { + /* Cs */ + sp->out_buffer[5+m*2]=sp->sos_cs[sp->plane_sample_offset+m]; + /* Td and Ta */ + sp->out_buffer[5+m*2+1]=sp->sos_tda[sp->plane_sample_offset+m]; + } + /* Ss */ + sp->out_buffer[5+sp->samples_per_pixel_per_plane*2]=0; + /* Se */ + sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+1]=63; + /* Ah and Al */ + sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+2]=0; + *len=8+sp->samples_per_pixel_per_plane*2; + *mem=(void*)sp->out_buffer; + sp->out_state++; +} + +static int +OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + *len=sp->in_buffer_togo; + *mem=(void*)sp->in_buffer_cur; + sp->in_buffer_togo=0; + if (sp->in_buffer_file_togo==0) + { + switch(sp->in_buffer_source) + { + case osibsStrile: + if (sp->in_buffer_next_strilein_buffer_strile_count) + sp->out_state=ososRst; + else + sp->out_state=ososEoi; + break; + case osibsEof: + sp->out_state=ososEoi; + break; + default: + break; + } + } + return(1); +} + +static void +OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_RST0+sp->restart_index; + sp->restart_index++; + if (sp->restart_index==8) + sp->restart_index=0; + *len=2; + *mem=(void*)sp->out_buffer; + sp->out_state=ososCompressed; +} + +static void +OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_EOI; + *len=2; + *mem=(void*)sp->out_buffer; +} + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_create_decompress(cinfo),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_header(cinfo,require_image),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_start_decompress(cinfo),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_scanlines(cinfo,scanlines,max_lines),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_raw_data(cinfo,data,max_lines),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static void +jpeg_encap_unwind(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + LONGJMP(sp->exit_jmpbuf,1); +} +#endif + +static void +OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo,buffer); + TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg", "%s", buffer); +} + +static void +OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo,buffer); + TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg", "%s", buffer); + jpeg_encap_unwind((TIFF*)(cinfo->client_data)); +} + +static void +OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo) +{ + (void)cinfo; +} + +static boolean +OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo) +{ + TIFF* tif=(TIFF*)cinfo->client_data; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + void* mem=0; + uint32 len=0; + if (OJPEGWriteStream(tif,&mem,&len)==0) + { + TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Premature end of JPEG data"); + jpeg_encap_unwind(tif); + } + sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=len; + sp->libjpeg_jpeg_source_mgr.next_input_byte=mem; + return(1); +} + +static void +OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes) +{ + TIFF* tif=(TIFF*)cinfo->client_data; + (void)num_bytes; + TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); + jpeg_encap_unwind(tif); +} + +static boolean +OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired) +{ + TIFF* tif=(TIFF*)cinfo->client_data; + (void)desired; + TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); + jpeg_encap_unwind(tif); + return(0); +} + +static void +OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo) +{ + (void)cinfo; +} + +#endif + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_open.c b/thirdparty/libtiff/tif_open.c new file mode 100644 index 00000000..3b3b2ce6 --- /dev/null +++ b/thirdparty/libtiff/tif_open.c @@ -0,0 +1,695 @@ +/* $Id: tif_open.c,v 1.33.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +static const long typemask[13] = { + (long)0L, /* TIFF_NOTYPE */ + (long)0x000000ffL, /* TIFF_BYTE */ + (long)0xffffffffL, /* TIFF_ASCII */ + (long)0x0000ffffL, /* TIFF_SHORT */ + (long)0xffffffffL, /* TIFF_LONG */ + (long)0xffffffffL, /* TIFF_RATIONAL */ + (long)0x000000ffL, /* TIFF_SBYTE */ + (long)0x000000ffL, /* TIFF_UNDEFINED */ + (long)0x0000ffffL, /* TIFF_SSHORT */ + (long)0xffffffffL, /* TIFF_SLONG */ + (long)0xffffffffL, /* TIFF_SRATIONAL */ + (long)0xffffffffL, /* TIFF_FLOAT */ + (long)0xffffffffL, /* TIFF_DOUBLE */ +}; +static const int bigTypeshift[13] = { + 0, /* TIFF_NOTYPE */ + 24, /* TIFF_BYTE */ + 0, /* TIFF_ASCII */ + 16, /* TIFF_SHORT */ + 0, /* TIFF_LONG */ + 0, /* TIFF_RATIONAL */ + 24, /* TIFF_SBYTE */ + 24, /* TIFF_UNDEFINED */ + 16, /* TIFF_SSHORT */ + 0, /* TIFF_SLONG */ + 0, /* TIFF_SRATIONAL */ + 0, /* TIFF_FLOAT */ + 0, /* TIFF_DOUBLE */ +}; +static const int litTypeshift[13] = { + 0, /* TIFF_NOTYPE */ + 0, /* TIFF_BYTE */ + 0, /* TIFF_ASCII */ + 0, /* TIFF_SHORT */ + 0, /* TIFF_LONG */ + 0, /* TIFF_RATIONAL */ + 0, /* TIFF_SBYTE */ + 0, /* TIFF_UNDEFINED */ + 0, /* TIFF_SSHORT */ + 0, /* TIFF_SLONG */ + 0, /* TIFF_SRATIONAL */ + 0, /* TIFF_FLOAT */ + 0, /* TIFF_DOUBLE */ +}; + +/* + * Dummy functions to fill the omitted client procedures. + */ +static int +_tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + (void) fd; (void) pbase; (void) psize; + return (0); +} + +static void +_tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; (void) base; (void) size; +} + +/* + * Initialize the shift & mask tables, and the + * byte swapping state according to the file + * contents and the machine architecture. + */ +static void +TIFFInitOrder(TIFF* tif, int magic) +{ + tif->tif_typemask = typemask; + if (magic == TIFF_BIGENDIAN) { + tif->tif_typeshift = bigTypeshift; +#ifndef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; +#endif + } else { + tif->tif_typeshift = litTypeshift; +#ifdef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; +#endif + } +} + +int +_TIFFgetMode(const char* mode, const char* module) +{ + int m = -1; + + switch (mode[0]) { + case 'r': + m = O_RDONLY; + if (mode[1] == '+') + m = O_RDWR; + break; + case 'w': + case 'a': + m = O_RDWR|O_CREAT; + if (mode[0] == 'w') + m |= O_TRUNC; + break; + default: + TIFFErrorExt(0, module, "\"%s\": Bad mode", mode); + break; + } + return (m); +} + +TIFF* +TIFFClientOpen( + const char* name, const char* mode, + thandle_t clientdata, + TIFFReadWriteProc readproc, + TIFFReadWriteProc writeproc, + TIFFSeekProc seekproc, + TIFFCloseProc closeproc, + TIFFSizeProc sizeproc, + TIFFMapFileProc mapproc, + TIFFUnmapFileProc unmapproc +) +{ + static const char module[] = "TIFFClientOpen"; + TIFF *tif; + int m; + const char* cp; + + m = _TIFFgetMode(mode, module); + if (m == -1) + goto bad2; + tif = (TIFF *)_TIFFmalloc(sizeof (TIFF) + strlen(name) + 1); + if (tif == NULL) { + TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name); + goto bad2; + } + _TIFFmemset(tif, 0, sizeof (*tif)); + tif->tif_name = (char *)tif + sizeof (TIFF); + strcpy(tif->tif_name, name); + tif->tif_mode = m &~ (O_CREAT|O_TRUNC); + tif->tif_curdir = (tdir_t) -1; /* non-existent directory */ + tif->tif_curoff = 0; + tif->tif_curstrip = (tstrip_t) -1; /* invalid strip */ + tif->tif_row = (uint32) -1; /* read/write pre-increment */ + tif->tif_clientdata = clientdata; + if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) { + TIFFErrorExt(clientdata, module, + "One of the client procedures is NULL pointer."); + goto bad2; + } + tif->tif_readproc = readproc; + tif->tif_writeproc = writeproc; + tif->tif_seekproc = seekproc; + tif->tif_closeproc = closeproc; + tif->tif_sizeproc = sizeproc; + if (mapproc) + tif->tif_mapproc = mapproc; + else + tif->tif_mapproc = _tiffDummyMapProc; + if (unmapproc) + tif->tif_unmapproc = unmapproc; + else + tif->tif_unmapproc = _tiffDummyUnmapProc; + _TIFFSetDefaultCompressionState(tif); /* setup default state */ + /* + * Default is to return data MSB2LSB and enable the + * use of memory-mapped files and strip chopping when + * a file is opened read-only. + */ + tif->tif_flags = FILLORDER_MSB2LSB; + if (m == O_RDONLY ) + tif->tif_flags |= TIFF_MAPPED; + +#ifdef STRIPCHOP_DEFAULT + if (m == O_RDONLY || m == O_RDWR) + tif->tif_flags |= STRIPCHOP_DEFAULT; +#endif + + /* + * Process library-specific flags in the open mode string. + * The following flags may be used to control intrinsic library + * behaviour that may or may not be desirable (usually for + * compatibility with some application that claims to support + * TIFF but only supports some braindead idea of what the + * vendor thinks TIFF is): + * + * 'l' use little-endian byte order for creating a file + * 'b' use big-endian byte order for creating a file + * 'L' read/write information using LSB2MSB bit order + * 'B' read/write information using MSB2LSB bit order + * 'H' read/write information using host bit order + * 'M' enable use of memory-mapped files when supported + * 'm' disable use of memory-mapped files + * 'C' enable strip chopping support when reading + * 'c' disable strip chopping support + * 'h' read TIFF header only, do not load the first IFD + * + * The use of the 'l' and 'b' flags is strongly discouraged. + * These flags are provided solely because numerous vendors, + * typically on the PC, do not correctly support TIFF; they + * only support the Intel little-endian byte order. This + * support is not configured by default because it supports + * the violation of the TIFF spec that says that readers *MUST* + * support both byte orders. It is strongly recommended that + * you not use this feature except to deal with busted apps + * that write invalid TIFF. And even in those cases you should + * bang on the vendors to fix their software. + * + * The 'L', 'B', and 'H' flags are intended for applications + * that can optimize operations on data by using a particular + * bit order. By default the library returns data in MSB2LSB + * bit order for compatibiltiy with older versions of this + * library. Returning data in the bit order of the native cpu + * makes the most sense but also requires applications to check + * the value of the FillOrder tag; something they probably do + * not do right now. + * + * The 'M' and 'm' flags are provided because some virtual memory + * systems exhibit poor behaviour when large images are mapped. + * These options permit clients to control the use of memory-mapped + * files on a per-file basis. + * + * The 'C' and 'c' flags are provided because the library support + * for chopping up large strips into multiple smaller strips is not + * application-transparent and as such can cause problems. The 'c' + * option permits applications that only want to look at the tags, + * for example, to get the unadulterated TIFF tag information. + */ + for (cp = mode; *cp; cp++) + switch (*cp) { + case 'b': +#ifndef WORDS_BIGENDIAN + if (m&O_CREAT) + tif->tif_flags |= TIFF_SWAB; +#endif + break; + case 'l': +#ifdef WORDS_BIGENDIAN + if ((m&O_CREAT)) + tif->tif_flags |= TIFF_SWAB; +#endif + break; + case 'B': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_MSB2LSB; + break; + case 'L': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_LSB2MSB; + break; + case 'H': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + HOST_FILLORDER; + break; + case 'M': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_MAPPED; + break; + case 'm': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_MAPPED; + break; + case 'C': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_STRIPCHOP; + break; + case 'c': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_STRIPCHOP; + break; + case 'h': + tif->tif_flags |= TIFF_HEADERONLY; + break; + } + /* + * Read in TIFF header. + */ + if (tif->tif_mode & O_TRUNC || + !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeader))) { + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, name, + "Cannot read TIFF header"); + goto bad; + } + /* + * Setup header and write. + */ +#ifdef WORDS_BIGENDIAN + tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB + ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; +#else + tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB + ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; +#endif + tif->tif_header.tiff_version = TIFF_VERSION; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif->tif_header.tiff_version); + tif->tif_header.tiff_diroff = 0; /* filled in later */ + + + /* + * The doc for "fopen" for some STD_C_LIBs says that if you + * open a file for modify ("+"), then you must fseek (or + * fflush?) between any freads and fwrites. This is not + * necessary on most systems, but has been shown to be needed + * on Solaris. + */ + TIFFSeekFile( tif, 0, SEEK_SET ); + + if (!WriteOK(tif, &tif->tif_header, sizeof (TIFFHeader))) { + TIFFErrorExt(tif->tif_clientdata, name, + "Error writing TIFF header"); + goto bad; + } + /* + * Setup the byte order handling. + */ + TIFFInitOrder(tif, tif->tif_header.tiff_magic); + /* + * Setup default directory. + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + tif->tif_diroff = 0; + tif->tif_dirlist = NULL; + tif->tif_dirlistsize = 0; + tif->tif_dirnumber = 0; + return (tif); + } + /* + * Setup the byte order handling. + */ + if (tif->tif_header.tiff_magic != TIFF_BIGENDIAN && + tif->tif_header.tiff_magic != TIFF_LITTLEENDIAN +#if MDI_SUPPORT + && +#if HOST_BIGENDIAN + tif->tif_header.tiff_magic != MDI_BIGENDIAN +#else + tif->tif_header.tiff_magic != MDI_LITTLEENDIAN +#endif + ) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF or MDI file, bad magic number %d (0x%x)", +#else + ) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad magic number %d (0x%x)", +#endif + tif->tif_header.tiff_magic, + tif->tif_header.tiff_magic); + goto bad; + } + TIFFInitOrder(tif, tif->tif_header.tiff_magic); + /* + * Swap header if required. + */ + if (tif->tif_flags & TIFF_SWAB) { + TIFFSwabShort(&tif->tif_header.tiff_version); + TIFFSwabLong(&tif->tif_header.tiff_diroff); + } + /* + * Now check version (if needed, it's been byte-swapped). + * Note that this isn't actually a version number, it's a + * magic number that doesn't change (stupid). + */ + if (tif->tif_header.tiff_version == TIFF_BIGTIFF_VERSION) { + TIFFErrorExt(tif->tif_clientdata, name, + "This is a BigTIFF file. This format not supported\n" + "by this version of libtiff." ); + goto bad; + } + if (tif->tif_header.tiff_version != TIFF_VERSION) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad version number %d (0x%x)", + tif->tif_header.tiff_version, + tif->tif_header.tiff_version); + goto bad; + } + tif->tif_flags |= TIFF_MYBUFFER; + tif->tif_rawcp = tif->tif_rawdata = 0; + tif->tif_rawdatasize = 0; + + /* + * Sometimes we do not want to read the first directory (for example, + * it may be broken) and want to proceed to other directories. I this + * case we use the TIFF_HEADERONLY flag to open file and return + * immediately after reading TIFF header. + */ + if (tif->tif_flags & TIFF_HEADERONLY) + return (tif); + + /* + * Setup initial directory. + */ + switch (mode[0]) { + case 'r': + tif->tif_nextdiroff = tif->tif_header.tiff_diroff; + /* + * Try to use a memory-mapped file if the client + * has not explicitly suppressed usage with the + * 'm' flag in the open mode (see above). + */ + if ((tif->tif_flags & TIFF_MAPPED) && + !TIFFMapFileContents(tif, (tdata_t*) &tif->tif_base, &tif->tif_size)) + tif->tif_flags &= ~TIFF_MAPPED; + if (TIFFReadDirectory(tif)) { + tif->tif_rawcc = -1; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (tif); + } + break; + case 'a': + /* + * New directories are automatically append + * to the end of the directory chain when they + * are written out (see TIFFWriteDirectory). + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + return (tif); + } +bad: + tif->tif_mode = O_RDONLY; /* XXX avoid flush */ + TIFFCleanup(tif); +bad2: + return ((TIFF*)0); +} + +/* + * Query functions to access private data. + */ + +/* + * Return open file's name. + */ +const char * +TIFFFileName(TIFF* tif) +{ + return (tif->tif_name); +} + +/* + * Set the file name. + */ +const char * +TIFFSetFileName(TIFF* tif, const char *name) +{ + const char* old_name = tif->tif_name; + tif->tif_name = (char *)name; + return (old_name); +} + +/* + * Return open file's I/O descriptor. + */ +int +TIFFFileno(TIFF* tif) +{ + return (tif->tif_fd); +} + +/* + * Set open file's I/O descriptor, and return previous value. + */ +int +TIFFSetFileno(TIFF* tif, int fd) +{ + int old_fd = tif->tif_fd; + tif->tif_fd = fd; + return old_fd; +} + +/* + * Return open file's clientdata. + */ +thandle_t +TIFFClientdata(TIFF* tif) +{ + return (tif->tif_clientdata); +} + +/* + * Set open file's clientdata, and return previous value. + */ +thandle_t +TIFFSetClientdata(TIFF* tif, thandle_t newvalue) +{ + thandle_t m = tif->tif_clientdata; + tif->tif_clientdata = newvalue; + return m; +} + +/* + * Return read/write mode. + */ +int +TIFFGetMode(TIFF* tif) +{ + return (tif->tif_mode); +} + +/* + * Return read/write mode. + */ +int +TIFFSetMode(TIFF* tif, int mode) +{ + int old_mode = tif->tif_mode; + tif->tif_mode = mode; + return (old_mode); +} + +/* + * Return nonzero if file is organized in + * tiles; zero if organized as strips. + */ +int +TIFFIsTiled(TIFF* tif) +{ + return (isTiled(tif)); +} + +/* + * Return current row being read/written. + */ +uint32 +TIFFCurrentRow(TIFF* tif) +{ + return (tif->tif_row); +} + +/* + * Return index of the current directory. + */ +tdir_t +TIFFCurrentDirectory(TIFF* tif) +{ + return (tif->tif_curdir); +} + +/* + * Return current strip. + */ +tstrip_t +TIFFCurrentStrip(TIFF* tif) +{ + return (tif->tif_curstrip); +} + +/* + * Return current tile. + */ +ttile_t +TIFFCurrentTile(TIFF* tif) +{ + return (tif->tif_curtile); +} + +/* + * Return nonzero if the file has byte-swapped data. + */ +int +TIFFIsByteSwapped(TIFF* tif) +{ + return ((tif->tif_flags & TIFF_SWAB) != 0); +} + +/* + * Return nonzero if the data is returned up-sampled. + */ +int +TIFFIsUpSampled(TIFF* tif) +{ + return (isUpSampled(tif)); +} + +/* + * Return nonzero if the data is returned in MSB-to-LSB bit order. + */ +int +TIFFIsMSB2LSB(TIFF* tif) +{ + return (isFillOrder(tif, FILLORDER_MSB2LSB)); +} + +/* + * Return nonzero if given file was written in big-endian order. + */ +int +TIFFIsBigEndian(TIFF* tif) +{ + return (tif->tif_header.tiff_magic == TIFF_BIGENDIAN); +} + +/* + * Return pointer to file read method. + */ +TIFFReadWriteProc +TIFFGetReadProc(TIFF* tif) +{ + return (tif->tif_readproc); +} + +/* + * Return pointer to file write method. + */ +TIFFReadWriteProc +TIFFGetWriteProc(TIFF* tif) +{ + return (tif->tif_writeproc); +} + +/* + * Return pointer to file seek method. + */ +TIFFSeekProc +TIFFGetSeekProc(TIFF* tif) +{ + return (tif->tif_seekproc); +} + +/* + * Return pointer to file close method. + */ +TIFFCloseProc +TIFFGetCloseProc(TIFF* tif) +{ + return (tif->tif_closeproc); +} + +/* + * Return pointer to file size requesting method. + */ +TIFFSizeProc +TIFFGetSizeProc(TIFF* tif) +{ + return (tif->tif_sizeproc); +} + +/* + * Return pointer to memory mapping method. + */ +TIFFMapFileProc +TIFFGetMapFileProc(TIFF* tif) +{ + return (tif->tif_mapproc); +} + +/* + * Return pointer to memory unmapping method. + */ +TIFFUnmapFileProc +TIFFGetUnmapFileProc(TIFF* tif) +{ + return (tif->tif_unmapproc); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_packbits.c b/thirdparty/libtiff/tif_packbits.c new file mode 100644 index 00000000..ee095f56 --- /dev/null +++ b/thirdparty/libtiff/tif_packbits.c @@ -0,0 +1,300 @@ +/* $Id: tif_packbits.c,v 1.13.2.2 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef PACKBITS_SUPPORT +/* + * TIFF Library. + * + * PackBits Compression Algorithm Support + */ +#include + +static int +PackBitsPreEncode(TIFF* tif, tsample_t s) +{ + (void) s; + + if (!(tif->tif_data = (tidata_t)_TIFFmalloc(sizeof(tsize_t)))) + return (0); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + *(tsize_t*)tif->tif_data = TIFFTileRowSize(tif); + else + *(tsize_t*)tif->tif_data = TIFFScanlineSize(tif); + return (1); +} + +static int +PackBitsPostEncode(TIFF* tif) +{ + if (tif->tif_data) + _TIFFfree(tif->tif_data); + return (1); +} + +/* + * NB: tidata is the type representing *(tidata_t); + * if tidata_t is made signed then this type must + * be adjusted accordingly. + */ +typedef unsigned char tidata; + +/* + * Encode a run of pixels. + */ +static int +PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + unsigned char* bp = (unsigned char*) buf; + tidata_t op, ep, lastliteral; + long n, slop; + int b; + enum { BASE, LITERAL, RUN, LITERAL_RUN } state; + + (void) s; + op = tif->tif_rawcp; + ep = tif->tif_rawdata + tif->tif_rawdatasize; + state = BASE; + lastliteral = 0; + while (cc > 0) { + /* + * Find the longest string of identical bytes. + */ + b = *bp++, cc--, n = 1; + for (; cc > 0 && b == *bp; cc--, bp++) + n++; + again: + if (op + 2 >= ep) { /* insure space for new data */ + /* + * Be careful about writing the last + * literal. Must write up to that point + * and then copy the remainder to the + * front of the buffer. + */ + if (state == LITERAL || state == LITERAL_RUN) { + slop = op - lastliteral; + tif->tif_rawcc += lastliteral - tif->tif_rawcp; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + while (slop-- > 0) + *op++ = *lastliteral++; + lastliteral = tif->tif_rawcp; + } else { + tif->tif_rawcc += op - tif->tif_rawcp; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + } + } + switch (state) { + case BASE: /* initial state, set run/literal */ + if (n > 1) { + state = RUN; + if (n > 128) { + *op++ = (tidata) -127; + *op++ = (tidataval_t) b; + n -= 128; + goto again; + } + *op++ = (tidataval_t)(-(n-1)); + *op++ = (tidataval_t) b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = (tidataval_t) b; + state = LITERAL; + } + break; + case LITERAL: /* last object was literal string */ + if (n > 1) { + state = LITERAL_RUN; + if (n > 128) { + *op++ = (tidata) -127; + *op++ = (tidataval_t) b; + n -= 128; + goto again; + } + *op++ = (tidataval_t)(-(n-1)); /* encode run */ + *op++ = (tidataval_t) b; + } else { /* extend literal */ + if (++(*lastliteral) == 127) + state = BASE; + *op++ = (tidataval_t) b; + } + break; + case RUN: /* last object was run */ + if (n > 1) { + if (n > 128) { + *op++ = (tidata) -127; + *op++ = (tidataval_t) b; + n -= 128; + goto again; + } + *op++ = (tidataval_t)(-(n-1)); + *op++ = (tidataval_t) b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = (tidataval_t) b; + state = LITERAL; + } + break; + case LITERAL_RUN: /* literal followed by a run */ + /* + * Check to see if previous run should + * be converted to a literal, in which + * case we convert literal-run-literal + * to a single literal. + */ + if (n == 1 && op[-2] == (tidata) -1 && + *lastliteral < 126) { + state = (((*lastliteral) += 2) == 127 ? + BASE : LITERAL); + op[-2] = op[-1]; /* replicate */ + } else + state = RUN; + goto again; + } + } + tif->tif_rawcc += op - tif->tif_rawcp; + tif->tif_rawcp = op; + return (1); +} + +/* + * Encode a rectangular chunk of pixels. We break it up + * into row-sized pieces to insure that encoded runs do + * not span rows. Otherwise, there can be problems with + * the decoder if data is read, for example, by scanlines + * when it was encoded by strips. + */ +static int +PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowsize = *(tsize_t*)tif->tif_data; + + while ((long)cc > 0) { + int chunk = rowsize; + + if( cc < chunk ) + chunk = cc; + + if (PackBitsEncode(tif, bp, chunk, s) < 0) + return (-1); + bp += chunk; + cc -= chunk; + } + return (1); +} + +static int +PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + char *bp; + tsize_t cc; + long n; + int b; + + (void) s; + bp = (char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + while (cc > 0 && (long)occ > 0) { + n = (long) *bp++, cc--; + /* + * Watch out for compilers that + * don't sign extend chars... + */ + if (n >= 128) + n -= 256; + if (n < 0) { /* replicate next byte -n+1 times */ + if (n == -128) /* nop */ + continue; + n = -n + 1; + if( occ < n ) + { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "PackBitsDecode: discarding %ld bytes " + "to avoid buffer overrun", + n - occ); + n = occ; + } + occ -= n; + b = *bp++, cc--; + while (n-- > 0) + *op++ = (tidataval_t) b; + } else { /* copy next n+1 bytes literally */ + if (occ < n + 1) + { + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "PackBitsDecode: discarding %ld bytes " + "to avoid buffer overrun", + n - occ + 1); + n = occ - 1; + } + _TIFFmemcpy(op, bp, ++n); + op += n; occ -= n; + bp += n; cc -= n; + } + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "PackBitsDecode: Not enough data for scanline %ld", + (long) tif->tif_row); + return (0); + } + return (1); +} + +int +TIFFInitPackBits(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = PackBitsDecode; + tif->tif_decodestrip = PackBitsDecode; + tif->tif_decodetile = PackBitsDecode; + tif->tif_preencode = PackBitsPreEncode; + tif->tif_postencode = PackBitsPostEncode; + tif->tif_encoderow = PackBitsEncode; + tif->tif_encodestrip = PackBitsEncodeChunk; + tif->tif_encodetile = PackBitsEncodeChunk; + return (1); +} +#endif /* PACKBITS_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_pixarlog.c b/thirdparty/libtiff/tif_pixarlog.c new file mode 100644 index 00000000..ed8eb402 --- /dev/null +++ b/thirdparty/libtiff/tif_pixarlog.c @@ -0,0 +1,1371 @@ +/* $Id: tif_pixarlog.c,v 1.15.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1996-1997 Sam Leffler + * Copyright (c) 1996 Pixar + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Pixar, Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef PIXARLOG_SUPPORT + +/* + * TIFF Library. + * PixarLog Compression Support + * + * Contributed by Dan McCoy. + * + * PixarLog film support uses the TIFF library to store companded + * 11 bit values into a tiff file, which are compressed using the + * zip compressor. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit or 8-bit unsigned integer values. + * + * On writing any of the above are converted into the internal + * 11-bit log format. In the case of 8 and 16 bit values, the + * input is assumed to be unsigned linear color values that represent + * the range 0-1. In the case of IEEE values, the 0-1 range is assumed to + * be the normal linear color range, in addition over 1 values are + * accepted up to a value of about 25.0 to encode "hot" hightlights and such. + * The encoding is lossless for 8-bit values, slightly lossy for the + * other bit depths. The actual color precision should be better + * than the human eye can perceive with extra room to allow for + * error introduced by further image computation. As with any quantized + * color format, it is possible to perform image calculations which + * expose the quantization error. This format should certainly be less + * susceptable to such errors than standard 8-bit encodings, but more + * susceptable than straight 16-bit or 32-bit encodings. + * + * On reading the internal format is converted to the desired output format. + * The program can request which format it desires by setting the internal + * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values: + * PIXARLOGDATAFMT_FLOAT = provide IEEE float values. + * PIXARLOGDATAFMT_16BIT = provide unsigned 16-bit integer values + * PIXARLOGDATAFMT_8BIT = provide unsigned 8-bit integer values + * + * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer + * values with the difference that if there are exactly three or four channels + * (rgb or rgba) it swaps the channel order (bgr or abgr). + * + * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly + * packed in 16-bit values. However no tools are supplied for interpreting + * these values. + * + * "hot" (over 1.0) areas written in floating point get clamped to + * 1.0 in the integer data types. + * + * When the file is closed after writing, the bit depth and sample format + * are set always to appear as if 8-bit data has been written into it. + * That way a naive program unaware of the particulars of the encoding + * gets the format it is most likely able to handle. + * + * The codec does it's own horizontal differencing step on the coded + * values so the libraries predictor stuff should be turned off. + * The codec also handle byte swapping the encoded values as necessary + * since the library does not have the information necessary + * to know the bit depth of the raw unencoded buffer. + * + */ + +#include "tif_predict.h" +#include "zlib.h" + +#include +#include +#include + +/* Tables for converting to/from 11 bit coded values */ + +#define TSIZE 2048 /* decode table size (11-bit tokens) */ +#define TSIZEP1 2049 /* Plus one for slop */ +#define ONE 1250 /* token value of 1.0 exactly */ +#define RATIO 1.004 /* nominal ratio for log part */ + +#define CODE_MASK 0x7ff /* 11 bits. */ + +static float Fltsize; +static float LogK1, LogK2; + +#define REPEAT(n, op) { int i; i=n; do { i--; op; } while (i>0); } + +static void +horizontalAccumulateF(uint16 *wp, int n, int stride, float *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = wp[0]]; + t1 = ToLinearF[cg = wp[1]]; + t2 = ToLinearF[cb = wp[2]]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + } + } else if (stride == 4) { + t0 = ToLinearF[cr = wp[0]]; + t1 = ToLinearF[cg = wp[1]]; + t2 = ToLinearF[cb = wp[2]]; + t3 = ToLinearF[ca = wp[3]]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + t3 = ToLinearF[(ca += wp[3]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + +#define SCALE12 2048.0F +#define CLAMP12(t) (((t) < 3071) ? (uint16) (t) : 3071) + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = wp[0]] * SCALE12; + t1 = ToLinearF[cg = wp[1]] * SCALE12; + t2 = ToLinearF[cb = wp[2]] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + } + } else if (stride == 4) { + t0 = ToLinearF[cr = wp[0]] * SCALE12; + t1 = ToLinearF[cg = wp[1]] * SCALE12; + t2 = ToLinearF[cb = wp[2]] * SCALE12; + t3 = ToLinearF[ca = wp[3]] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + } + } else { + REPEAT(stride, t0 = ToLinearF[*wp&mask] * SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; t0 = ToLinearF[wp[stride]&mask]*SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op, + uint16 *ToLinear16) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear16[cr = wp[0]]; + op[1] = ToLinear16[cg = wp[1]]; + op[2] = ToLinear16[cb = wp[2]]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear16[cr = wp[0]]; + op[1] = ToLinear16[cg = wp[1]]; + op[2] = ToLinear16[cb = wp[2]]; + op[3] = ToLinear16[ca = wp[3]]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + op[3] = ToLinear16[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * Returns the log encoded 11-bit values with the horizontal + * differencing undone. + */ +static void +horizontalAccumulate11(uint16 *wp, int n, int stride, uint16 *op) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = cr = wp[0]; op[1] = cg = wp[1]; op[2] = cb = wp[2]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = (cr += wp[0]) & mask; + op[1] = (cg += wp[1]) & mask; + op[2] = (cb += wp[2]) & mask; + } + } else if (stride == 4) { + op[0] = cr = wp[0]; op[1] = cg = wp[1]; + op[2] = cb = wp[2]; op[3] = ca = wp[3]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = (cr += wp[0]) & mask; + op[1] = (cg += wp[1]) & mask; + op[2] = (cb += wp[2]) & mask; + op[3] = (ca += wp[3]) & mask; + } + } else { + REPEAT(stride, *op = *wp&mask; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = *wp&mask; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear8[cr = wp[0]]; + op[1] = ToLinear8[cg = wp[1]]; + op[2] = ToLinear8[cb = wp[2]]; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 3; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear8[cr = wp[0]]; + op[1] = ToLinear8[cg = wp[1]]; + op[2] = ToLinear8[cb = wp[2]]; + op[3] = ToLinear8[ca = wp[3]]; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + op[3] = ToLinear8[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + + +static void +horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + register unsigned char t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = 0; + t1 = ToLinear8[cb = wp[2]]; + t2 = ToLinear8[cg = wp[1]]; + t3 = ToLinear8[cr = wp[0]]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 4; + op[0] = 0; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else if (stride == 4) { + t0 = ToLinear8[ca = wp[3]]; + t1 = ToLinear8[cb = wp[2]]; + t2 = ToLinear8[cg = wp[1]]; + t3 = ToLinear8[cr = wp[0]]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + t0 = ToLinear8[(ca += wp[3]) & mask]; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * State block for each open TIFF + * file using PixarLog compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + uint16 *tbuf; + uint16 stride; + int state; + int user_datafmt; + int quality; +#define PLSTATE_INIT 1 + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + + float *ToLinearF; + uint16 *ToLinear16; + unsigned char *ToLinear8; + uint16 *FromLT2; + uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16 *From8; + +} PixarLogState; + +static int +PixarLogMakeTables(PixarLogState *sp) +{ + +/* + * We make several tables here to convert between various external + * representations (float, 16-bit, and 8-bit) and the internal + * 11-bit companded representation. The 11-bit representation has two + * distinct regions. A linear bottom end up through .018316 in steps + * of about .000073, and a region of constant ratio up to about 25. + * These floating point numbers are stored in the main table ToLinearF. + * All other tables are derived from this one. The tables (and the + * ratios) are continuous at the internal seam. + */ + + int nlin, lt2size; + int i, j; + double b, c, linstep, v; + float *ToLinearF; + uint16 *ToLinear16; + unsigned char *ToLinear8; + uint16 *FromLT2; + uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16 *From8; + + c = log(RATIO); + nlin = (int)(1./c); /* nlin must be an integer */ + c = 1./nlin; + b = exp(-c*ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */ + linstep = b*c*exp(1.); + + LogK1 = (float)(1./c); /* if (v >= 2) token = k1*log(v*k2) */ + LogK2 = (float)(1./b); + lt2size = (int)(2./linstep) + 1; + FromLT2 = (uint16 *)_TIFFmalloc(lt2size*sizeof(uint16)); + From14 = (uint16 *)_TIFFmalloc(16384*sizeof(uint16)); + From8 = (uint16 *)_TIFFmalloc(256*sizeof(uint16)); + ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float)); + ToLinear16 = (uint16 *)_TIFFmalloc(TSIZEP1 * sizeof(uint16)); + ToLinear8 = (unsigned char *)_TIFFmalloc(TSIZEP1 * sizeof(unsigned char)); + if (FromLT2 == NULL || From14 == NULL || From8 == NULL || + ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) { + if (FromLT2) _TIFFfree(FromLT2); + if (From14) _TIFFfree(From14); + if (From8) _TIFFfree(From8); + if (ToLinearF) _TIFFfree(ToLinearF); + if (ToLinear16) _TIFFfree(ToLinear16); + if (ToLinear8) _TIFFfree(ToLinear8); + sp->FromLT2 = NULL; + sp->From14 = NULL; + sp->From8 = NULL; + sp->ToLinearF = NULL; + sp->ToLinear16 = NULL; + sp->ToLinear8 = NULL; + return 0; + } + + j = 0; + + for (i = 0; i < nlin; i++) { + v = i * linstep; + ToLinearF[j++] = (float)v; + } + + for (i = nlin; i < TSIZE; i++) + ToLinearF[j++] = (float)(b*exp(c*i)); + + ToLinearF[2048] = ToLinearF[2047]; + + for (i = 0; i < TSIZEP1; i++) { + v = ToLinearF[i]*65535.0 + 0.5; + ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16)v; + v = ToLinearF[i]*255.0 + 0.5; + ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v; + } + + j = 0; + for (i = 0; i < lt2size; i++) { + if ((i*linstep)*(i*linstep) > ToLinearF[j]*ToLinearF[j+1]) + j++; + FromLT2[i] = j; + } + + /* + * Since we lose info anyway on 16-bit data, we set up a 14-bit + * table and shift 16-bit values down two bits on input. + * saves a little table space. + */ + j = 0; + for (i = 0; i < 16384; i++) { + while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From14[i] = j; + } + + j = 0; + for (i = 0; i < 256; i++) { + while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From8[i] = j; + } + + Fltsize = (float)(lt2size/2); + + sp->ToLinearF = ToLinearF; + sp->ToLinear16 = ToLinear16; + sp->ToLinear8 = ToLinear8; + sp->FromLT2 = FromLT2; + sp->From14 = From14; + sp->From8 = From8; + + return 1; +} + +#define DecoderState(tif) ((PixarLogState*) (tif)->tif_data) +#define EncoderState(tif) ((PixarLogState*) (tif)->tif_data) + +static int PixarLogEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int PixarLogDecode(TIFF*, tidata_t, tsize_t, tsample_t); + +#define PIXARLOGDATAFMT_UNKNOWN -1 + +static int +PixarLogGuessDataFmt(TIFFDirectory *td) +{ + int guess = PIXARLOGDATAFMT_UNKNOWN; + int format = td->td_sampleformat; + + /* If the user didn't tell us his datafmt, + * take our best guess from the bitspersample. + */ + switch (td->td_bitspersample) { + case 32: + if (format == SAMPLEFORMAT_IEEEFP) + guess = PIXARLOGDATAFMT_FLOAT; + break; + case 16: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_16BIT; + break; + case 12: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT) + guess = PIXARLOGDATAFMT_12BITPICIO; + break; + case 11: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_11BITLOG; + break; + case 8: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_8BIT; + break; + } + + return guess; +} + +static uint32 +multiply(size_t m1, size_t m2) +{ + uint32 bytes = m1 * m2; + + if (m1 && bytes / m1 != m2) + bytes = 0; + + return bytes; +} + +static int +PixarLogSetupDecode(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + tsize_t tbuf_size; + static const char module[] = "PixarLogSetupDecode"; + + assert(sp != NULL); + + /* Make sure no byte swapping happens on the data + * after decompression. */ + tif->tif_postdecode = _TIFFNoPostDecode; + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + tbuf_size = multiply(multiply(multiply(sp->stride, td->td_imagewidth), + td->td_rowsperstrip), sizeof(uint16)); + if (tbuf_size == 0) + return (0); + sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size); + if (sp->tbuf == NULL) + return (0); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFErrorExt(tif->tif_clientdata, module, + "PixarLog compression can't handle bits depth/data format combination (depth: %d)", + td->td_bitspersample); + return (0); + } + + if (inflateInit(&sp->stream) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +PixarLogPreDecode(TIFF* tif, tsample_t s) +{ + PixarLogState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_in = tif->tif_rawdata; + sp->stream.avail_in = tif->tif_rawcc; + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +PixarLogDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + static const char module[] = "PixarLogDecode"; + int i, nsamples, llen; + uint16 *up; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + nsamples = occ / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + nsamples = occ / sizeof(uint16); /* XXX uint16 == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + nsamples = occ; + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + (void) s; + assert(sp != NULL); + sp->stream.next_out = (unsigned char *) sp->tbuf; + sp->stream.avail_out = nsamples * sizeof(uint16); + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) { + break; /* XXX */ + } + if (state == Z_DATA_ERROR) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Decoding error at scanline %d, %s", + tif->tif_name, tif->tif_row, sp->stream.msg); + if (inflateSync(&sp->stream) != Z_OK) + return (0); + continue; + } + if (state != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (sp->stream.avail_out > 0); + + /* hopefully, we got all the bytes we needed */ + if (sp->stream.avail_out != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Not enough data at scanline %d (short %d bytes)", + tif->tif_name, tif->tif_row, sp->stream.avail_out); + return (0); + } + + up = sp->tbuf; + /* Swap bytes in the data if from a different endian machine. */ + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfShort(up, nsamples); + + /* + * if llen is not an exact multiple of nsamples, the decode operation + * may overflow the output buffer, so truncate it enough to prevent + * that but still salvage as much data as possible. + */ + if (nsamples % llen) { + TIFFWarningExt(tif->tif_clientdata, module, + "%s: stride %d is not a multiple of sample count, " + "%d, data truncated.", tif->tif_name, llen, nsamples); + nsamples -= nsamples % llen; + } + + for (i = 0; i < nsamples; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalAccumulateF(up, llen, sp->stride, + (float *)op, sp->ToLinearF); + op += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalAccumulate16(up, llen, sp->stride, + (uint16 *)op, sp->ToLinear16); + op += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_12BITPICIO: + horizontalAccumulate12(up, llen, sp->stride, + (int16 *)op, sp->ToLinearF); + op += llen * sizeof(int16); + break; + case PIXARLOGDATAFMT_11BITLOG: + horizontalAccumulate11(up, llen, sp->stride, + (uint16 *)op); + op += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalAccumulate8(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + case PIXARLOGDATAFMT_8BITABGR: + horizontalAccumulate8abgr(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "PixarLogDecode: unsupported bits/sample: %d", + td->td_bitspersample); + return (0); + } + } + + return (1); +} + +static int +PixarLogSetupEncode(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = EncoderState(tif); + tsize_t tbuf_size; + static const char module[] = "PixarLogSetupEncode"; + + assert(sp != NULL); + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + tbuf_size = multiply(multiply(multiply(sp->stride, td->td_imagewidth), + td->td_rowsperstrip), sizeof(uint16)); + if (tbuf_size == 0) + return (0); + sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size); + if (sp->tbuf == NULL) + return (0); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFErrorExt(tif->tif_clientdata, module, "PixarLog compression can't handle %d bit linear encodings", td->td_bitspersample); + return (0); + } + + if (deflateInit(&sp->stream, sp->quality) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +PixarLogPreEncode(TIFF* tif, tsample_t s) +{ + PixarLogState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + return (deflateReset(&sp->stream) == Z_OK); +} + +static void +horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2) +{ + + int32 r1, g1, b1, a1, r2, g2, b2, a2, mask; + float fltsize = Fltsize; + +#define CLAMP(v) ( (v<(float)0.) ? 0 \ + : (v<(float)2.) ? FromLT2[(int)(v*fltsize)] \ + : (v>(float)24.2) ? 2047 \ + : LogK1*log(v*LogK2) + 0.5 ) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = (uint16) CLAMP(ip[0]); + g2 = wp[1] = (uint16) CLAMP(ip[1]); + b2 = wp[2] = (uint16) CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = (uint16) CLAMP(ip[0]); + g2 = wp[1] = (uint16) CLAMP(ip[1]); + b2 = wp[2] = (uint16) CLAMP(ip[2]); + a2 = wp[3] = (uint16) CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + a1 = (int32) CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; + } + } else { + ip += n - 1; /* point to last one */ + wp += n - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp--; ip--) + } + } +} + +static void +horizontalDifference16(unsigned short *ip, int n, int stride, + unsigned short *wp, uint16 *From14) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +/* assumption is unsigned pixel values */ +#undef CLAMP +#define CLAMP(v) From14[(v) >> 2] + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; + } + } else { + ip += n - 1; /* point to last one */ + wp += n - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + + +static void +horizontalDifference8(unsigned char *ip, int n, int stride, + unsigned short *wp, uint16 *From8) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +#undef CLAMP +#define CLAMP(v) (From8[(v)]) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + r1 = CLAMP(ip[3]); wp[3] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[4]); wp[4] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[5]); wp[5] = (b1-b2) & mask; b2 = b1; + wp += 3; + ip += 3; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + r1 = CLAMP(ip[4]); wp[4] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[5]); wp[5] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[6]); wp[6] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[7]); wp[7] = (a1-a2) & mask; a2 = a1; + wp += 4; + ip += 4; + } + } else { + wp += n + stride - 1; /* point to last one */ + ip += n + stride - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + +/* + * Encode a chunk of pixels. + */ +static int +PixarLogEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState *sp = EncoderState(tif); + static const char module[] = "PixarLogEncode"; + int i, n, llen; + unsigned short * up; + + (void) s; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + n = cc / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + n = cc / sizeof(uint16); /* XXX uint16 == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + n = cc; + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalDifferenceF((float *)bp, llen, + sp->stride, up, sp->FromLT2); + bp += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalDifference16((uint16 *)bp, llen, + sp->stride, up, sp->From14); + bp += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalDifference8((unsigned char *)bp, llen, + sp->stride, up, sp->From8); + bp += llen * sizeof(unsigned char); + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + } + + sp->stream.next_in = (unsigned char *) sp->tbuf; + sp->stream.avail_in = n * sizeof(uint16); + + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Encoder error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ + +static int +PixarLogPostEncode(TIFF* tif) +{ + PixarLogState *sp = EncoderState(tif); + static const char module[] = "PixarLogPostEncode"; + int state; + + sp->stream.avail_in = 0; + + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if (sp->stream.avail_out != (uint32)tif->tif_rawdatasize) { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +PixarLogClose(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + + /* In a really sneaky maneuver, on close, we covertly modify both + * bitspersample and sampleformat in the directory to indicate + * 8-bit linear. This way, the decode "just works" even for + * readers that don't know about PixarLog, or how to set + * the PIXARLOGDATFMT pseudo-tag. + */ + td->td_bitspersample = 8; + td->td_sampleformat = SAMPLEFORMAT_UINT; +} + +static void +PixarLogCleanup(TIFF* tif) +{ + PixarLogState* sp = (PixarLogState*) tif->tif_data; + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->FromLT2) _TIFFfree(sp->FromLT2); + if (sp->From14) _TIFFfree(sp->From14); + if (sp->From8) _TIFFfree(sp->From8); + if (sp->ToLinearF) _TIFFfree(sp->ToLinearF); + if (sp->ToLinear16) _TIFFfree(sp->ToLinear16); + if (sp->ToLinear8) _TIFFfree(sp->ToLinear8); + if (sp->state&PLSTATE_INIT) { + if (tif->tif_mode == O_RDONLY) + inflateEnd(&sp->stream); + else + deflateEnd(&sp->stream); + } + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +PixarLogVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + PixarLogState *sp = (PixarLogState *)tif->tif_data; + int result; + static const char module[] = "PixarLogVSetField"; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + sp->quality = va_arg(ap, int); + if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) { + if (deflateParams(&sp->stream, + sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } + return (1); + case TIFFTAG_PIXARLOGDATAFMT: + sp->user_datafmt = va_arg(ap, int); + /* Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_11BITLOG: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_12BITPICIO: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + break; + case PIXARLOGDATAFMT_16BIT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_FLOAT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + break; + } + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1; + tif->tif_scanlinesize = TIFFScanlineSize(tif); + result = 1; /* NB: pseudo tag */ + break; + default: + result = (*sp->vsetparent)(tif, tag, ap); + } + return (result); +} + +static int +PixarLogVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + PixarLogState *sp = (PixarLogState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + *va_arg(ap, int*) = sp->quality; + break; + case TIFFTAG_PIXARLOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFFieldInfo pixarlogFieldInfo[] = { + {TIFFTAG_PIXARLOGDATAFMT,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""}, + {TIFFTAG_PIXARLOGQUALITY,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""} +}; + +int +TIFFInitPixarLog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitPixarLog"; + + PixarLogState* sp; + + assert(scheme == COMPRESSION_PIXARLOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, pixarlogFieldInfo, + TIFFArrayCount(pixarlogFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging PixarLog codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (PixarLogState)); + if (tif->tif_data == NULL) + goto bad; + sp = (PixarLogState*) tif->tif_data; + _TIFFmemset(sp, 0, sizeof (*sp)); + sp->stream.data_type = Z_BINARY; + sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = PixarLogSetupDecode; + tif->tif_predecode = PixarLogPreDecode; + tif->tif_decoderow = PixarLogDecode; + tif->tif_decodestrip = PixarLogDecode; + tif->tif_decodetile = PixarLogDecode; + tif->tif_setupencode = PixarLogSetupEncode; + tif->tif_preencode = PixarLogPreEncode; + tif->tif_postencode = PixarLogPostEncode; + tif->tif_encoderow = PixarLogEncode; + tif->tif_encodestrip = PixarLogEncode; + tif->tif_encodetile = PixarLogEncode; + tif->tif_close = PixarLogClose; + tif->tif_cleanup = PixarLogCleanup; + + /* Override SetField so we can handle our private pseudo-tag */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = PixarLogVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = PixarLogVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* we don't wish to use the predictor, + * the default is none, which predictor value 1 + */ + (void) TIFFPredictorInit(tif); + + /* + * build the companding tables + */ + PixarLogMakeTables(sp); + + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for PixarLog state block"); + return (0); +} +#endif /* PIXARLOG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_predict.c b/thirdparty/libtiff/tif_predict.c new file mode 100644 index 00000000..bbc221f2 --- /dev/null +++ b/thirdparty/libtiff/tif_predict.c @@ -0,0 +1,736 @@ +/* $Id: tif_predict.c,v 1.11.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Predictor Tag Support (used by multiple codecs). + */ +#include "tiffiop.h" +#include "tif_predict.h" + +#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data) + +static void horAcc8(TIFF*, tidata_t, tsize_t); +static void horAcc16(TIFF*, tidata_t, tsize_t); +static void horAcc32(TIFF*, tidata_t, tsize_t); +static void swabHorAcc16(TIFF*, tidata_t, tsize_t); +static void swabHorAcc32(TIFF*, tidata_t, tsize_t); +static void horDiff8(TIFF*, tidata_t, tsize_t); +static void horDiff16(TIFF*, tidata_t, tsize_t); +static void horDiff32(TIFF*, tidata_t, tsize_t); +static void fpAcc(TIFF*, tidata_t, tsize_t); +static void fpDiff(TIFF*, tidata_t, tsize_t); +static int PredictorDecodeRow(TIFF*, tidata_t, tsize_t, tsample_t); +static int PredictorDecodeTile(TIFF*, tidata_t, tsize_t, tsample_t); +static int PredictorEncodeRow(TIFF*, tidata_t, tsize_t, tsample_t); +static int PredictorEncodeTile(TIFF*, tidata_t, tsize_t, tsample_t); + +static int +PredictorSetup(TIFF* tif) +{ + static const char module[] = "PredictorSetup"; + + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (sp->predictor) /* no differencing */ + { + case PREDICTOR_NONE: + return 1; + case PREDICTOR_HORIZONTAL: + if (td->td_bitspersample != 8 + && td->td_bitspersample != 16 + && td->td_bitspersample != 32) { + TIFFErrorExt(tif->tif_clientdata, module, + "Horizontal differencing \"Predictor\" not supported with %d-bit samples", + td->td_bitspersample); + return 0; + } + break; + case PREDICTOR_FLOATINGPOINT: + if (td->td_sampleformat != SAMPLEFORMAT_IEEEFP) { + TIFFErrorExt(tif->tif_clientdata, module, + "Floating point \"Predictor\" not supported with %d data format", + td->td_sampleformat); + return 0; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "\"Predictor\" value %d not supported", + sp->predictor); + return 0; + } + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + sp->rowsize = TIFFTileRowSize(tif); + else + sp->rowsize = TIFFScanlineSize(tif); + + return 1; +} + +static int +PredictorSetupDecode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif)) + return 0; + + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->decodepfunc = horAcc8; break; + case 16: sp->decodepfunc = horAcc16; break; + case 32: sp->decodepfunc = horAcc32; break; + } + /* + * Override default decoding method with one that does the + * predictor stuff. + */ + if( tif->tif_decoderow != PredictorDecodeRow ) + { + sp->decoderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->decodestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->decodetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + } + /* + * If the data is horizontally differenced 16-bit data that + * requires byte-swapping, then it must be byte swapped before + * the accumulation step. We do this with a special-purpose + * routine and override the normal post decoding logic that + * the library setup when the directory was read. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (sp->decodepfunc == horAcc16) { + sp->decodepfunc = swabHorAcc16; + tif->tif_postdecode = _TIFFNoPostDecode; + } else if (sp->decodepfunc == horAcc32) { + sp->decodepfunc = swabHorAcc32; + tif->tif_postdecode = _TIFFNoPostDecode; + } + } + } + + else if (sp->predictor == 3) { + sp->decodepfunc = fpAcc; + /* + * Override default decoding method with one that does the + * predictor stuff. + */ + if( tif->tif_decoderow != PredictorDecodeRow ) + { + sp->decoderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->decodestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->decodetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + } + /* + * The data should not be swapped outside of the floating + * point predictor, the accumulation routine should return + * byres in the native order. + */ + if (tif->tif_flags & TIFF_SWAB) { + tif->tif_postdecode = _TIFFNoPostDecode; + } + /* + * Allocate buffer to keep the decoded bytes before + * rearranging in the ight order + */ + } + + return 1; +} + +static int +PredictorSetupEncode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupencode)(tif) || !PredictorSetup(tif)) + return 0; + + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->encodepfunc = horDiff8; break; + case 16: sp->encodepfunc = horDiff16; break; + case 32: sp->encodepfunc = horDiff32; break; + } + /* + * Override default encoding method with one that does the + * predictor stuff. + */ + if( tif->tif_encoderow != PredictorEncodeRow ) + { + sp->encoderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->encodestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->encodetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + } + + else if (sp->predictor == 3) { + sp->encodepfunc = fpDiff; + /* + * Override default encoding method with one that does the + * predictor stuff. + */ + if( tif->tif_encoderow != PredictorEncodeRow ) + { + sp->encoderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->encodestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->encodetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + } + + return 1; +} + +#define REPEAT4(n, op) \ + switch (n) { \ + default: { int i; for (i = n-4; i > 0; i--) { op; } } \ + case 4: op; \ + case 3: op; \ + case 2: op; \ + case 1: op; \ + case 0: ; \ + } + +static void +horAcc8(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + + char* cp = (char*) cp0; + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + do { + cc -= 3, cp += 3; + cp[0] = (char) (cr += cp[0]); + cp[1] = (char) (cg += cp[1]); + cp[2] = (char) (cb += cp[2]); + } while ((int32) cc > 0); + } else if (stride == 4) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + unsigned int ca = cp[3]; + do { + cc -= 4, cp += 4; + cp[0] = (char) (cr += cp[0]); + cp[1] = (char) (cg += cp[1]); + cp[2] = (char) (cb += cp[2]); + cp[3] = (char) (ca += cp[3]); + } while ((int32) cc > 0); + } else { + do { + REPEAT4(stride, cp[stride] = + (char) (cp[stride] + *cp); cp++) + cc -= stride; + } while ((int32) cc > 0); + } + } +} + +static void +swabHorAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint16* wp = (uint16*) cp0; + tsize_t wc = cc / 2; + + if (wc > stride) { + TIFFSwabArrayOfShort(wp, wc); + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while ((int32) wc > 0); + } +} + +static void +horAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint16* wp = (uint16*) cp0; + tsize_t wc = cc / 2; + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while ((int32) wc > 0); + } +} + +static void +swabHorAcc32(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint32* wp = (uint32*) cp0; + tsize_t wc = cc / 4; + + if (wc > stride) { + TIFFSwabArrayOfLong(wp, wc); + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while ((int32) wc > 0); + } +} + +static void +horAcc32(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint32* wp = (uint32*) cp0; + tsize_t wc = cc / 4; + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while ((int32) wc > 0); + } +} + +/* + * Floating point predictor accumulation routine. + */ +static void +fpAcc(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint32 bps = tif->tif_dir.td_bitspersample / 8; + tsize_t wc = cc / bps; + tsize_t count = cc; + uint8 *cp = (uint8 *) cp0; + uint8 *tmp = (uint8 *)_TIFFmalloc(cc); + + if (!tmp) + return; + + while (count > stride) { + REPEAT4(stride, cp[stride] += cp[0]; cp++) + count -= stride; + } + + _TIFFmemcpy(tmp, cp0, cc); + cp = (uint8 *) cp0; + for (count = 0; count < wc; count++) { + uint32 byte; + for (byte = 0; byte < bps; byte++) { +#if WORDS_BIGENDIAN + cp[bps * count + byte] = tmp[byte * wc + count]; +#else + cp[bps * count + byte] = + tmp[(bps - byte - 1) * wc + count]; +#endif + } + } + _TIFFfree(tmp); +} + +/* + * Decode a scanline and apply the predictor routine. + */ +static int +PredictorDecodeRow(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->decoderow != NULL); + assert(sp->decodepfunc != NULL); + + if ((*sp->decoderow)(tif, op0, occ0, s)) { + (*sp->decodepfunc)(tif, op0, occ0); + return 1; + } else + return 0; +} + +/* + * Decode a tile/strip and apply the predictor routine. + * Note that horizontal differencing must be done on a + * row-by-row basis. The width of a "row" has already + * been calculated at pre-decode time according to the + * strip/tile dimensions. + */ +static int +PredictorDecodeTile(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->decodetile != NULL); + + if ((*sp->decodetile)(tif, op0, occ0, s)) { + tsize_t rowsize = sp->rowsize; + assert(rowsize > 0); + assert(sp->decodepfunc != NULL); + while ((long)occ0 > 0) { + (*sp->decodepfunc)(tif, op0, (tsize_t) rowsize); + occ0 -= rowsize; + op0 += rowsize; + } + return 1; + } else + return 0; +} + +static void +horDiff8(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + char* cp = (char*) cp0; + + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + int r1, g1, b1; + int r2 = cp[0]; + int g2 = cp[1]; + int b2 = cp[2]; + do { + r1 = cp[3]; cp[3] = r1-r2; r2 = r1; + g1 = cp[4]; cp[4] = g1-g2; g2 = g1; + b1 = cp[5]; cp[5] = b1-b2; b2 = b1; + cp += 3; + } while ((int32)(cc -= 3) > 0); + } else if (stride == 4) { + int r1, g1, b1, a1; + int r2 = cp[0]; + int g2 = cp[1]; + int b2 = cp[2]; + int a2 = cp[3]; + do { + r1 = cp[4]; cp[4] = r1-r2; r2 = r1; + g1 = cp[5]; cp[5] = g1-g2; g2 = g1; + b1 = cp[6]; cp[6] = b1-b2; b2 = b1; + a1 = cp[7]; cp[7] = a1-a2; a2 = a1; + cp += 4; + } while ((int32)(cc -= 4) > 0); + } else { + cp += cc - 1; + do { + REPEAT4(stride, cp[stride] -= cp[0]; cp--) + } while ((int32)(cc -= stride) > 0); + } + } +} + +static void +horDiff16(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + int16 *wp = (int16*) cp0; + tsize_t wc = cc/2; + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] -= wp[0]; wp--) + wc -= stride; + } while ((int32) wc > 0); + } +} + +static void +horDiff32(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + int32 *wp = (int32*) cp0; + tsize_t wc = cc/4; + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] -= wp[0]; wp--) + wc -= stride; + } while ((int32) wc > 0); + } +} + +/* + * Floating point predictor differencing routine. + */ +static void +fpDiff(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint32 bps = tif->tif_dir.td_bitspersample / 8; + tsize_t wc = cc / bps; + tsize_t count; + uint8 *cp = (uint8 *) cp0; + uint8 *tmp = (uint8 *)_TIFFmalloc(cc); + + if (!tmp) + return; + + _TIFFmemcpy(tmp, cp0, cc); + for (count = 0; count < wc; count++) { + uint32 byte; + for (byte = 0; byte < bps; byte++) { +#if WORDS_BIGENDIAN + cp[byte * wc + count] = tmp[bps * count + byte]; +#else + cp[(bps - byte - 1) * wc + count] = + tmp[bps * count + byte]; +#endif + } + } + _TIFFfree(tmp); + + cp = (uint8 *) cp0; + cp += cc - stride - 1; + for (count = cc; count > stride; count -= stride) + REPEAT4(stride, cp[stride] -= cp[0]; cp--) +} + +static int +PredictorEncodeRow(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encoderow != NULL); + + /* XXX horizontal differencing alters user's data XXX */ + (*sp->encodepfunc)(tif, bp, cc); + return (*sp->encoderow)(tif, bp, cc, s); +} + +static int +PredictorEncodeTile(TIFF* tif, tidata_t bp0, tsize_t cc0, tsample_t s) +{ + static const char module[] = "PredictorEncodeTile"; + TIFFPredictorState *sp = PredictorState(tif); + uint8 *working_copy; + tsize_t cc = cc0, rowsize; + unsigned char* bp; + int result_code; + + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encodetile != NULL); + + /* + * Do predictor manipulation in a working buffer to avoid altering + * the callers buffer. http://trac.osgeo.org/gdal/ticket/1965 + */ + working_copy = (uint8*) _TIFFmalloc(cc0); + if( working_copy == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Out of memory allocating %d byte temp buffer.", + cc0 ); + return 0; + } + memcpy( working_copy, bp0, cc0 ); + bp = working_copy; + + rowsize = sp->rowsize; + assert(rowsize > 0); + assert((cc0%rowsize)==0); + while (cc > 0) { + (*sp->encodepfunc)(tif, bp, rowsize); + cc -= rowsize; + bp += rowsize; + } + result_code = (*sp->encodetile)(tif, working_copy, cc0, s); + + _TIFFfree( working_copy ); + + return result_code; +} + +#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */ + +static const TIFFFieldInfo predictFieldInfo[] = { + { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, FIELD_PREDICTOR, + FALSE, FALSE, "Predictor" }, +}; + +static int +PredictorVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->vsetparent != NULL); + + switch (tag) { + case TIFFTAG_PREDICTOR: + sp->predictor = (uint16) va_arg(ap, int); + TIFFSetFieldBit(tif, FIELD_PREDICTOR); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +static int +PredictorVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->vgetparent != NULL); + + switch (tag) { + case TIFFTAG_PREDICTOR: + *va_arg(ap, uint16*) = sp->predictor; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static void +PredictorPrintDir(TIFF* tif, FILE* fd, long flags) +{ + TIFFPredictorState* sp = PredictorState(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_PREDICTOR)) { + fprintf(fd, " Predictor: "); + switch (sp->predictor) { + case 1: fprintf(fd, "none "); break; + case 2: fprintf(fd, "horizontal differencing "); break; + case 3: fprintf(fd, "floating point predictor "); break; + } + fprintf(fd, "%u (0x%x)\n", sp->predictor, sp->predictor); + } + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +int +TIFFPredictorInit(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + assert(sp != 0); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, predictFieldInfo, + TIFFArrayCount(predictFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFPredictorInit", + "Merging Predictor codec-specific tags failed"); + return 0; + } + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = + PredictorVGetField;/* hook for predictor tag */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = + PredictorVSetField;/* hook for predictor tag */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = + PredictorPrintDir; /* hook for predictor tag */ + + sp->setupdecode = tif->tif_setupdecode; + tif->tif_setupdecode = PredictorSetupDecode; + sp->setupencode = tif->tif_setupencode; + tif->tif_setupencode = PredictorSetupEncode; + + sp->predictor = 1; /* default value */ + sp->encodepfunc = NULL; /* no predictor routine */ + sp->decodepfunc = NULL; /* no predictor routine */ + return 1; +} + +int +TIFFPredictorCleanup(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + tif->tif_setupdecode = sp->setupdecode; + tif->tif_setupencode = sp->setupencode; + + return 1; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_predict.h b/thirdparty/libtiff/tif_predict.h new file mode 100644 index 00000000..da0ad989 --- /dev/null +++ b/thirdparty/libtiff/tif_predict.h @@ -0,0 +1,77 @@ +/* $Id: tif_predict.h,v 1.3.2.2 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFPREDICT_ +#define _TIFFPREDICT_ +/* + * ``Library-private'' Support for the Predictor Tag + */ + +/* + * Codecs that want to support the Predictor tag must place + * this structure first in their private state block so that + * the predictor code can cast tif_data to find its state. + */ +typedef struct { + int predictor; /* predictor tag value */ + int stride; /* sample stride over data */ + tsize_t rowsize; /* tile/strip row size */ + + TIFFCodeMethod encoderow; /* parent codec encode/decode row */ + TIFFCodeMethod encodestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod encodetile; /* parent codec encode/decode tile */ + TIFFPostMethod encodepfunc; /* horizontal differencer */ + + TIFFCodeMethod decoderow; /* parent codec encode/decode row */ + TIFFCodeMethod decodestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod decodetile; /* parent codec encode/decode tile */ + TIFFPostMethod decodepfunc; /* horizontal accumulator */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFBoolMethod setupdecode; /* super-class method */ + TIFFBoolMethod setupencode; /* super-class method */ +} TIFFPredictorState; + +#if defined(__cplusplus) +extern "C" { +#endif +extern int TIFFPredictorInit(TIFF*); +extern int TIFFPredictorCleanup(TIFF*); +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFPREDICT_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_print.c b/thirdparty/libtiff/tif_print.c new file mode 100644 index 00000000..d9e4435c --- /dev/null +++ b/thirdparty/libtiff/tif_print.c @@ -0,0 +1,646 @@ +/* $Id: tif_print.c,v 1.36.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Printing Support + */ +#include "tiffiop.h" +#include +#include +#include + +static const char *photoNames[] = { + "min-is-white", /* PHOTOMETRIC_MINISWHITE */ + "min-is-black", /* PHOTOMETRIC_MINISBLACK */ + "RGB color", /* PHOTOMETRIC_RGB */ + "palette color (RGB from colormap)", /* PHOTOMETRIC_PALETTE */ + "transparency mask", /* PHOTOMETRIC_MASK */ + "separated", /* PHOTOMETRIC_SEPARATED */ + "YCbCr", /* PHOTOMETRIC_YCBCR */ + "7 (0x7)", + "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */ +}; +#define NPHOTONAMES (sizeof (photoNames) / sizeof (photoNames[0])) + +static const char *orientNames[] = { + "0 (0x0)", + "row 0 top, col 0 lhs", /* ORIENTATION_TOPLEFT */ + "row 0 top, col 0 rhs", /* ORIENTATION_TOPRIGHT */ + "row 0 bottom, col 0 rhs", /* ORIENTATION_BOTRIGHT */ + "row 0 bottom, col 0 lhs", /* ORIENTATION_BOTLEFT */ + "row 0 lhs, col 0 top", /* ORIENTATION_LEFTTOP */ + "row 0 rhs, col 0 top", /* ORIENTATION_RIGHTTOP */ + "row 0 rhs, col 0 bottom", /* ORIENTATION_RIGHTBOT */ + "row 0 lhs, col 0 bottom", /* ORIENTATION_LEFTBOT */ +}; +#define NORIENTNAMES (sizeof (orientNames) / sizeof (orientNames[0])) + +static void +_TIFFPrintField(FILE* fd, const TIFFFieldInfo *fip, + uint32 value_count, void *raw_data) +{ + uint32 j; + + fprintf(fd, " %s: ", fip->field_name); + + for(j = 0; j < value_count; j++) { + if(fip->field_type == TIFF_BYTE) + fprintf(fd, "%u", ((uint8 *) raw_data)[j]); + else if(fip->field_type == TIFF_UNDEFINED) + fprintf(fd, "0x%x", + (unsigned int) ((unsigned char *) raw_data)[j]); + else if(fip->field_type == TIFF_SBYTE) + fprintf(fd, "%d", ((int8 *) raw_data)[j]); + else if(fip->field_type == TIFF_SHORT) + fprintf(fd, "%u", ((uint16 *) raw_data)[j]); + else if(fip->field_type == TIFF_SSHORT) + fprintf(fd, "%d", ((int16 *) raw_data)[j]); + else if(fip->field_type == TIFF_LONG) + fprintf(fd, "%lu", + (unsigned long)((uint32 *) raw_data)[j]); + else if(fip->field_type == TIFF_SLONG) + fprintf(fd, "%ld", (long)((int32 *) raw_data)[j]); + else if(fip->field_type == TIFF_RATIONAL + || fip->field_type == TIFF_SRATIONAL + || fip->field_type == TIFF_FLOAT) + fprintf(fd, "%f", ((float *) raw_data)[j]); + else if(fip->field_type == TIFF_IFD) + fprintf(fd, "0x%ulx", ((uint32 *) raw_data)[j]); + else if(fip->field_type == TIFF_ASCII) { + fprintf(fd, "%s", (char *) raw_data); + break; + } + else if(fip->field_type == TIFF_DOUBLE) + fprintf(fd, "%f", ((double *) raw_data)[j]); + else if(fip->field_type == TIFF_FLOAT) + fprintf(fd, "%f", ((float *)raw_data)[j]); + else { + fprintf(fd, ""); + break; + } + + if(j < value_count - 1) + fprintf(fd, ","); + } + + fprintf(fd, "\n"); +} + +static int +_TIFFPrettyPrintField(TIFF* tif, FILE* fd, ttag_t tag, + uint32 value_count, void *raw_data) +{ + //TIFFDirectory *td = &tif->tif_dir; + + switch (tag) + { + case TIFFTAG_INKSET: + fprintf(fd, " Ink Set: "); + switch (*((uint16*)raw_data)) { + case INKSET_CMYK: + fprintf(fd, "CMYK\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + *((uint16*)raw_data), + *((uint16*)raw_data)); + break; + } + return 1; + case TIFFTAG_DOTRANGE: + fprintf(fd, " Dot Range: %u-%u\n", + ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]); + return 1; + case TIFFTAG_WHITEPOINT: + fprintf(fd, " White Point: %g-%g\n", + ((float *)raw_data)[0], ((float *)raw_data)[1]); return 1; + case TIFFTAG_REFERENCEBLACKWHITE: + { + uint16 i; + + fprintf(fd, " Reference Black/White:\n"); + for (i = 0; i < 3; i++) + fprintf(fd, " %2d: %5g %5g\n", i, + ((float *)raw_data)[2*i+0], + ((float *)raw_data)[2*i+1]); + return 1; + } + case TIFFTAG_XMLPACKET: + { + uint32 i; + + fprintf(fd, " XMLPacket (XMP Metadata):\n" ); + for(i = 0; i < value_count; i++) + fputc(((char *)raw_data)[i], fd); + fprintf( fd, "\n" ); + return 1; + } + case TIFFTAG_RICHTIFFIPTC: + /* + * XXX: for some weird reason RichTIFFIPTC tag + * defined as array of LONG values. + */ + fprintf(fd, + " RichTIFFIPTC Data: , %lu bytes\n", + (unsigned long) value_count * 4); + return 1; + case TIFFTAG_PHOTOSHOP: + fprintf(fd, " Photoshop Data: , %lu bytes\n", + (unsigned long) value_count); + return 1; + case TIFFTAG_ICCPROFILE: + fprintf(fd, " ICC Profile: , %lu bytes\n", + (unsigned long) value_count); + return 1; + case TIFFTAG_STONITS: + fprintf(fd, + " Sample to Nits conversion factor: %.4e\n", + *((double*)raw_data)); + return 1; + } + + return 0; +} + +/* + * Print the contents of the current directory + * to the specified stdio file stream. + */ +void +TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) +{ + TIFFDirectory *td = &tif->tif_dir; + char *sep; + uint16 i; + long l, n; + + fprintf(fd, "TIFF Directory at offset 0x%lx (%lu)\n", + (unsigned long)tif->tif_diroff, (unsigned long)tif->tif_diroff); + if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) { + fprintf(fd, " Subfile Type:"); + sep = " "; + if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) { + fprintf(fd, "%sreduced-resolution image", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_PAGE) { + fprintf(fd, "%smulti-page document", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_MASK) + fprintf(fd, "%stransparency mask", sep); + fprintf(fd, " (%lu = 0x%lx)\n", + (long) td->td_subfiletype, (long) td->td_subfiletype); + } + if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) { + fprintf(fd, " Image Width: %lu Image Length: %lu", + (unsigned long) td->td_imagewidth, (unsigned long) td->td_imagelength); + if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH)) + fprintf(fd, " Image Depth: %lu", + (unsigned long) td->td_imagedepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) { + fprintf(fd, " Tile Width: %lu Tile Length: %lu", + (unsigned long) td->td_tilewidth, (unsigned long) td->td_tilelength); + if (TIFFFieldSet(tif,FIELD_TILEDEPTH)) + fprintf(fd, " Tile Depth: %lu", + (unsigned long) td->td_tiledepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_RESOLUTION)) { + fprintf(fd, " Resolution: %g, %g", + td->td_xresolution, td->td_yresolution); + if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) { + switch (td->td_resolutionunit) { + case RESUNIT_NONE: + fprintf(fd, " (unitless)"); + break; + case RESUNIT_INCH: + fprintf(fd, " pixels/inch"); + break; + case RESUNIT_CENTIMETER: + fprintf(fd, " pixels/cm"); + break; + default: + fprintf(fd, " (unit %u = 0x%x)", + td->td_resolutionunit, + td->td_resolutionunit); + break; + } + } + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_POSITION)) + fprintf(fd, " Position: %g, %g\n", + td->td_xposition, td->td_yposition); + if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + fprintf(fd, " Bits/Sample: %u\n", td->td_bitspersample); + if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) { + fprintf(fd, " Sample Format: "); + switch (td->td_sampleformat) { + case SAMPLEFORMAT_VOID: + fprintf(fd, "void\n"); + break; + case SAMPLEFORMAT_INT: + fprintf(fd, "signed integer\n"); + break; + case SAMPLEFORMAT_UINT: + fprintf(fd, "unsigned integer\n"); + break; + case SAMPLEFORMAT_IEEEFP: + fprintf(fd, "IEEE floating point\n"); + break; + case SAMPLEFORMAT_COMPLEXINT: + fprintf(fd, "complex signed integer\n"); + break; + case SAMPLEFORMAT_COMPLEXIEEEFP: + fprintf(fd, "complex IEEE floating point\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_sampleformat, td->td_sampleformat); + break; + } + } + if (TIFFFieldSet(tif,FIELD_COMPRESSION)) { + const TIFFCodec* c = TIFFFindCODEC(td->td_compression); + fprintf(fd, " Compression Scheme: "); + if (c) + fprintf(fd, "%s\n", c->name); + else + fprintf(fd, "%u (0x%x)\n", + td->td_compression, td->td_compression); + } + if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) { + fprintf(fd, " Photometric Interpretation: "); + if (td->td_photometric < NPHOTONAMES) + fprintf(fd, "%s\n", photoNames[td->td_photometric]); + else { + switch (td->td_photometric) { + case PHOTOMETRIC_LOGL: + fprintf(fd, "CIE Log2(L)\n"); + break; + case PHOTOMETRIC_LOGLUV: + fprintf(fd, "CIE Log2(L) (u',v')\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_photometric, td->td_photometric); + break; + } + } + } + if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES) && td->td_extrasamples) { + fprintf(fd, " Extra Samples: %u<", td->td_extrasamples); + sep = ""; + for (i = 0; i < td->td_extrasamples; i++) { + switch (td->td_sampleinfo[i]) { + case EXTRASAMPLE_UNSPECIFIED: + fprintf(fd, "%sunspecified", sep); + break; + case EXTRASAMPLE_ASSOCALPHA: + fprintf(fd, "%sassoc-alpha", sep); + break; + case EXTRASAMPLE_UNASSALPHA: + fprintf(fd, "%sunassoc-alpha", sep); + break; + default: + fprintf(fd, "%s%u (0x%x)", sep, + td->td_sampleinfo[i], td->td_sampleinfo[i]); + break; + } + sep = ", "; + } + fprintf(fd, ">\n"); + } + if (TIFFFieldSet(tif,FIELD_INKNAMES)) { + char* cp; + fprintf(fd, " Ink Names: "); + i = td->td_samplesperpixel; + sep = ""; + for (cp = td->td_inknames; i > 0; cp = strchr(cp,'\0')+1, i--) { + fputs(sep, fd); + _TIFFprintAscii(fd, cp); + sep = ", "; + } + fputs("\n", fd); + } + if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) { + fprintf(fd, " Thresholding: "); + switch (td->td_threshholding) { + case THRESHHOLD_BILEVEL: + fprintf(fd, "bilevel art scan\n"); + break; + case THRESHHOLD_HALFTONE: + fprintf(fd, "halftone or dithered scan\n"); + break; + case THRESHHOLD_ERRORDIFFUSE: + fprintf(fd, "error diffused\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_threshholding, td->td_threshholding); + break; + } + } + if (TIFFFieldSet(tif,FIELD_FILLORDER)) { + fprintf(fd, " FillOrder: "); + switch (td->td_fillorder) { + case FILLORDER_MSB2LSB: + fprintf(fd, "msb-to-lsb\n"); + break; + case FILLORDER_LSB2MSB: + fprintf(fd, "lsb-to-msb\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_fillorder, td->td_fillorder); + break; + } + } + if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING)) + { + /* + * For hacky reasons (see tif_jpeg.c - JPEGFixupTestSubsampling), + * we need to fetch this rather than trust what is in our + * structures. + */ + uint16 subsampling[2]; + + TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, + subsampling + 0, subsampling + 1 ); + fprintf(fd, " YCbCr Subsampling: %u, %u\n", + subsampling[0], subsampling[1] ); + } + if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) { + fprintf(fd, " YCbCr Positioning: "); + switch (td->td_ycbcrpositioning) { + case YCBCRPOSITION_CENTERED: + fprintf(fd, "centered\n"); + break; + case YCBCRPOSITION_COSITED: + fprintf(fd, "cosited\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_ycbcrpositioning, td->td_ycbcrpositioning); + break; + } + } + if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS)) + fprintf(fd, " Halftone Hints: light %u dark %u\n", + td->td_halftonehints[0], td->td_halftonehints[1]); + if (TIFFFieldSet(tif,FIELD_ORIENTATION)) { + fprintf(fd, " Orientation: "); + if (td->td_orientation < NORIENTNAMES) + fprintf(fd, "%s\n", orientNames[td->td_orientation]); + else + fprintf(fd, "%u (0x%x)\n", + td->td_orientation, td->td_orientation); + } + if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + fprintf(fd, " Samples/Pixel: %u\n", td->td_samplesperpixel); + if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) { + fprintf(fd, " Rows/Strip: "); + if (td->td_rowsperstrip == (uint32) -1) + fprintf(fd, "(infinite)\n"); + else + fprintf(fd, "%lu\n", (unsigned long) td->td_rowsperstrip); + } + if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE)) + fprintf(fd, " Min Sample Value: %u\n", td->td_minsamplevalue); + if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) + fprintf(fd, " Max Sample Value: %u\n", td->td_maxsamplevalue); + if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) + fprintf(fd, " SMin Sample Value: %g\n", + td->td_sminsamplevalue); + if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) + fprintf(fd, " SMax Sample Value: %g\n", + td->td_smaxsamplevalue); + if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) { + fprintf(fd, " Planar Configuration: "); + switch (td->td_planarconfig) { + case PLANARCONFIG_CONTIG: + fprintf(fd, "single image plane\n"); + break; + case PLANARCONFIG_SEPARATE: + fprintf(fd, "separate image planes\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_planarconfig, td->td_planarconfig); + break; + } + } + if (TIFFFieldSet(tif,FIELD_PAGENUMBER)) + fprintf(fd, " Page Number: %u-%u\n", + td->td_pagenumber[0], td->td_pagenumber[1]); + if (TIFFFieldSet(tif,FIELD_COLORMAP)) { + fprintf(fd, " Color Map: "); + if (flags & TIFFPRINT_COLORMAP) { + fprintf(fd, "\n"); + n = 1L<td_bitspersample; + for (l = 0; l < n; l++) + fprintf(fd, " %5lu: %5u %5u %5u\n", + l, + td->td_colormap[0][l], + td->td_colormap[1][l], + td->td_colormap[2][l]); + } else + fprintf(fd, "(present)\n"); + } + if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) { + fprintf(fd, " Transfer Function: "); + if (flags & TIFFPRINT_CURVES) { + fprintf(fd, "\n"); + n = 1L<td_bitspersample; + for (l = 0; l < n; l++) { + fprintf(fd, " %2lu: %5u", + l, td->td_transferfunction[0][l]); + for (i = 1; i < td->td_samplesperpixel; i++) + fprintf(fd, " %5u", + td->td_transferfunction[i][l]); + fputc('\n', fd); + } + } else + fprintf(fd, "(present)\n"); + } + if (TIFFFieldSet(tif, FIELD_SUBIFD) && (td->td_subifd)) { + fprintf(fd, " SubIFD Offsets:"); + for (i = 0; i < td->td_nsubifd; i++) + fprintf(fd, " %5lu", (long) td->td_subifd[i]); + fputc('\n', fd); + } + + /* + ** Custom tag support. + */ + { + int i; + short count; + + count = (short) TIFFGetTagListCount(tif); + for(i = 0; i < count; i++) { + ttag_t tag = TIFFGetTagListEntry(tif, i); + const TIFFFieldInfo *fip; + uint32 value_count; + int mem_alloc = 0; + void *raw_data; + + fip = TIFFFieldWithTag(tif, tag); + if(fip == NULL) + continue; + + if(fip->field_passcount) { + if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) + continue; + } else { + if (fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2) + value_count = 1; + else if (fip->field_readcount == TIFF_SPP) + value_count = td->td_samplesperpixel; + else + value_count = fip->field_readcount; + if ((fip->field_type == TIFF_ASCII + || fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2 + || fip->field_readcount == TIFF_SPP + || value_count > 1) + && fip->field_tag != TIFFTAG_PAGENUMBER + && fip->field_tag != TIFFTAG_HALFTONEHINTS + && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING + && fip->field_tag != TIFFTAG_DOTRANGE) { + if(TIFFGetField(tif, tag, &raw_data) != 1) + continue; + } else if (fip->field_tag != TIFFTAG_PAGENUMBER + && fip->field_tag != TIFFTAG_HALFTONEHINTS + && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING + && fip->field_tag != TIFFTAG_DOTRANGE) { + raw_data = _TIFFmalloc( + _TIFFDataSize(fip->field_type) + * value_count); + mem_alloc = 1; + if(TIFFGetField(tif, tag, raw_data) != 1) { + _TIFFfree(raw_data); + continue; + } + } else { + /* + * XXX: Should be fixed and removed, see the + * notes related to TIFFTAG_PAGENUMBER, + * TIFFTAG_HALFTONEHINTS, + * TIFFTAG_YCBCRSUBSAMPLING and + * TIFFTAG_DOTRANGE tags in tif_dir.c. */ + char *tmp; + raw_data = _TIFFmalloc( + _TIFFDataSize(fip->field_type) + * value_count); + tmp = raw_data; + mem_alloc = 1; + if(TIFFGetField(tif, tag, tmp, + tmp + _TIFFDataSize(fip->field_type)) != 1) { + _TIFFfree(raw_data); + continue; + } + } + } + + /* + * Catch the tags which needs to be specially handled and + * pretty print them. If tag not handled in + * _TIFFPrettyPrintField() fall down and print it as any other + * tag. + */ + if (_TIFFPrettyPrintField(tif, fd, tag, value_count, raw_data)) { + if(mem_alloc) + _TIFFfree(raw_data); + continue; + } + else + _TIFFPrintField(fd, fip, value_count, raw_data); + + if(mem_alloc) + _TIFFfree(raw_data); + } + } + + if (tif->tif_tagmethods.printdir) + (*tif->tif_tagmethods.printdir)(tif, fd, flags); + if ((flags & TIFFPRINT_STRIPS) && + TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) { + tstrip_t s; + + fprintf(fd, " %lu %s:\n", + (long) td->td_nstrips, + isTiled(tif) ? "Tiles" : "Strips"); + for (s = 0; s < td->td_nstrips; s++) + fprintf(fd, " %3lu: [%8lu, %8lu]\n", + (unsigned long) s, + (unsigned long) td->td_stripoffset[s], + (unsigned long) td->td_stripbytecount[s]); + } +} + +void +_TIFFprintAscii(FILE* fd, const char* cp) +{ + for (; *cp != '\0'; cp++) { + const char* tp; + + if (isprint((int)*cp)) { + fputc(*cp, fd); + continue; + } + for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++) + if (*tp++ == *cp) + break; + if (*tp) + fprintf(fd, "\\%c", *tp); + else + fprintf(fd, "\\%03o", *cp & 0xff); + } +} + +void +_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value) +{ + fprintf(fd, " %s: \"", name); + _TIFFprintAscii(fd, value); + fprintf(fd, "\"\n"); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_read.c b/thirdparty/libtiff/tif_read.c new file mode 100644 index 00000000..8ac0ae66 --- /dev/null +++ b/thirdparty/libtiff/tif_read.c @@ -0,0 +1,750 @@ +/* $Id: tif_read.c,v 1.16.2.3 2010-06-09 14:32:47 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * Scanline-oriented Read Support + */ +#include "tiffiop.h" +#include + + int TIFFFillStrip(TIFF*, tstrip_t); + int TIFFFillTile(TIFF*, ttile_t); +static int TIFFStartStrip(TIFF*, tstrip_t); +static int TIFFStartTile(TIFF*, ttile_t); +static int TIFFCheckRead(TIFF*, int); + +#define NOSTRIP ((tstrip_t) -1) /* undefined state */ +#define NOTILE ((ttile_t) -1) /* undefined state */ + +/* + * Seek to a random row+sample in a file. + */ +static int +TIFFSeek(TIFF* tif, uint32 row, tsample_t sample) +{ + register TIFFDirectory *td = &tif->tif_dir; + tstrip_t strip; + + if (row >= td->td_imagelength) { /* out of range */ + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Row out of range, max %lu", + (unsigned long) row, + (unsigned long) td->td_imagelength); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return (0); + } + strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + if (strip != tif->tif_curstrip) { /* different strip, refill */ + if (!TIFFFillStrip(tif, strip)) + return (0); + } else if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: backup + * to the start and then decode forward (below). + * + * NB: If you're planning on lots of random access within a + * strip, it's better to just read and decode the entire + * strip, and then access the decoded data in a random fashion. + */ + if (!TIFFStartStrip(tif, strip)) + return (0); + } + if (row != tif->tif_row) { + /* + * Seek forward to the desired row. + */ + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (0); + tif->tif_row = row; + } + return (1); +} + +int +TIFFReadScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) +{ + int e; + + if (!TIFFCheckRead(tif, 0)) + return (-1); + if( (e = TIFFSeek(tif, row, sample)) != 0) { + /* + * Decompress desired row into user buffer. + */ + e = (*tif->tif_decoderow) + (tif, (tidata_t) buf, tif->tif_scanlinesize, sample); + + /* we are now poised at the beginning of the next row */ + tif->tif_row = row + 1; + + if (e) + (*tif->tif_postdecode)(tif, (tidata_t) buf, + tif->tif_scanlinesize); + } + return (e > 0 ? 1 : -1); +} + +/* + * Read a strip of data and decompress the specified + * amount into the user-supplied buffer. + */ +tsize_t +TIFFReadEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 nrows; + tsize_t stripsize; + tstrip_t sep_strip, strips_per_sep; + + if (!TIFFCheckRead(tif, 0)) + return (-1); + if (strip >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%ld: Strip out of range, max %ld", + (long) strip, (long) td->td_nstrips); + return (-1); + } + /* + * Calculate the strip size according to the number of + * rows in the strip (check for truncated last strip on any + * of the separations). + */ + if( td->td_rowsperstrip >= td->td_imagelength ) + strips_per_sep = 1; + else + strips_per_sep = (td->td_imagelength+td->td_rowsperstrip-1) + / td->td_rowsperstrip; + + sep_strip = strip % strips_per_sep; + + if (sep_strip != strips_per_sep-1 || + (nrows = td->td_imagelength % td->td_rowsperstrip) == 0) + nrows = td->td_rowsperstrip; + + stripsize = TIFFVStripSize(tif, nrows); + if (size == (tsize_t) -1) + size = stripsize; + else if (size > stripsize) + size = stripsize; + if (TIFFFillStrip(tif, strip) + && (*tif->tif_decodestrip)(tif, (tidata_t) buf, size, + (tsample_t)(strip / td->td_stripsperimage)) > 0 ) { + (*tif->tif_postdecode)(tif, (tidata_t) buf, size); + return (size); + } else + return ((tsize_t) -1); +} + +static tsize_t +TIFFReadRawStrip1(TIFF* tif, + tstrip_t strip, tdata_t buf, tsize_t size, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (!isMapped(tif)) { + tsize_t cc; + + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error at scanline %lu, strip %lu", + tif->tif_name, + (unsigned long) tif->tif_row, (unsigned long) strip); + return (-1); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Read error at scanline %lu; got %lu bytes, expected %lu", + tif->tif_name, + (unsigned long) tif->tif_row, + (unsigned long) cc, + (unsigned long) size); + return (-1); + } + } else { + if (td->td_stripoffset[strip] + size > tif->tif_size) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu", + tif->tif_name, + (unsigned long) tif->tif_row, + (unsigned long) strip, + (unsigned long) tif->tif_size - td->td_stripoffset[strip], + (unsigned long) size); + return (-1); + } + _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip], + size); + } + return (size); +} + +/* + * Read a strip of data from the file. + */ +tsize_t +TIFFReadRawStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size) +{ + static const char module[] = "TIFFReadRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + /* + * FIXME: butecount should have tsize_t type, but for now libtiff + * defines tsize_t as a signed 32-bit integer and we are losing + * ability to read arrays larger than 2^31 bytes. So we are using + * uint32 instead of tsize_t here. + */ + uint32 bytecount; + + if (!TIFFCheckRead(tif, 0)) + return ((tsize_t) -1); + if (strip >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Strip out of range, max %lu", + (unsigned long) strip, + (unsigned long) td->td_nstrips); + return ((tsize_t) -1); + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme does not support access to raw uncompressed data"); + return ((tsize_t) -1); + } + bytecount = td->td_stripbytecount[strip]; + if (bytecount <= 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Invalid strip byte count, strip %lu", + (unsigned long) bytecount, (unsigned long) strip); + return ((tsize_t) -1); + } + if (size != (tsize_t)-1 && (uint32)size < bytecount) + bytecount = size; + return (TIFFReadRawStrip1(tif, strip, buf, bytecount, module)); +} + +/* + * Read the specified strip and setup for decoding. The data buffer is + * expanded, as necessary, to hold the strip's data. + */ +int +TIFFFillStrip(TIFF* tif, tstrip_t strip) +{ + static const char module[] = "TIFFFillStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + /* + * FIXME: butecount should have tsize_t type, but for now + * libtiff defines tsize_t as a signed 32-bit integer and we + * are losing ability to read arrays larger than 2^31 bytes. + * So we are using uint32 instead of tsize_t here. + */ + uint32 bytecount = td->td_stripbytecount[strip]; + if (bytecount <= 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Invalid strip byte count %lu, strip %lu", + tif->tif_name, (unsigned long) bytecount, + (unsigned long) strip); + return (0); + } + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is + * going to handle this operation itself. In this + * case, avoid copying the raw data and instead just + * reference the data from the memory mapped file + * image. This assumes that the decompression + * routines do not modify the contents of the raw data + * buffer (if they try to, the application will get a + * fault since the file is mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + /* + * We must check for overflow, potentially causing + * an OOB read. Instead of simple + * + * td->td_stripoffset[strip]+bytecount > tif->tif_size + * + * comparison (which can overflow) we do the following + * two comparisons: + */ + if (bytecount > tif->tif_size || + td->td_stripoffset[strip] > tif->tif_size - bytecount) { + /* + * This error message might seem strange, but + * it's what would happen if a read were done + * instead. + */ + TIFFErrorExt(tif->tif_clientdata, module, + + "%s: Read error on strip %lu; " + "got %lu bytes, expected %lu", + tif->tif_name, (unsigned long) strip, + (unsigned long) tif->tif_size - td->td_stripoffset[strip], + (unsigned long) bytecount); + tif->tif_curstrip = NOSTRIP; + return (0); + } + tif->tif_rawdatasize = bytecount; + tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip]; + } else { + /* + * Expand raw data buffer, if needed, to hold data + * strip coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + if (bytecount > (uint32)tif->tif_rawdatasize) { + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, + module, + "%s: Data buffer too small to hold strip %lu", + tif->tif_name, + (unsigned long) strip); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, + TIFFroundup(bytecount, 1024))) + return (0); + } + if ((uint32)TIFFReadRawStrip1(tif, strip, + (unsigned char *)tif->tif_rawdata, + bytecount, module) != bytecount) + return (0); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, bytecount); + } + } + return (TIFFStartStrip(tif, strip)); +} + +/* + * Tile-oriented Read Support + * Contributed by Nancy Cam (Silicon Graphics). + */ + +/* + * Read and decompress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tsize_t +TIFFReadTile(TIFF* tif, + tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s)) + return (-1); + return (TIFFReadEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1)); +} + +/* + * Read a tile of data and decompress the specified + * amount into the user-supplied buffer. + */ +tsize_t +TIFFReadEncodedTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t tilesize = tif->tif_tilesize; + + if (!TIFFCheckRead(tif, 1)) + return (-1); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%ld: Tile out of range, max %ld", + (long) tile, (unsigned long) td->td_nstrips); + return (-1); + } + if (size == (tsize_t) -1) + size = tilesize; + else if (size > tilesize) + size = tilesize; + if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif, + (tidata_t) buf, size, (tsample_t)(tile/td->td_stripsperimage))) { + (*tif->tif_postdecode)(tif, (tidata_t) buf, size); + return (size); + } else + return (-1); +} + +static tsize_t +TIFFReadRawTile1(TIFF* tif, + ttile_t tile, tdata_t buf, tsize_t size, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (!isMapped(tif)) { + tsize_t cc; + + if (!SeekOK(tif, td->td_stripoffset[tile])) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error at row %ld, col %ld, tile %ld", + tif->tif_name, + (long) tif->tif_row, + (long) tif->tif_col, + (long) tile); + return ((tsize_t) -1); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Read error at row %ld, col %ld; got %lu bytes, expected %lu", + tif->tif_name, + (long) tif->tif_row, + (long) tif->tif_col, + (unsigned long) cc, + (unsigned long) size); + return ((tsize_t) -1); + } + } else { + if (td->td_stripoffset[tile] + size > tif->tif_size) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Read error at row %ld, col %ld, tile %ld; got %lu bytes, expected %lu", + tif->tif_name, + (long) tif->tif_row, + (long) tif->tif_col, + (long) tile, + (unsigned long) tif->tif_size - td->td_stripoffset[tile], + (unsigned long) size); + return ((tsize_t) -1); + } + _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[tile], size); + } + return (size); +} + +/* + * Read a tile of data from the file. + */ +tsize_t +TIFFReadRawTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size) +{ + static const char module[] = "TIFFReadRawTile"; + TIFFDirectory *td = &tif->tif_dir; + /* + * FIXME: butecount should have tsize_t type, but for now libtiff + * defines tsize_t as a signed 32-bit integer and we are losing + * ability to read arrays larger than 2^31 bytes. So we are using + * uint32 instead of tsize_t here. + */ + uint32 bytecount; + + if (!TIFFCheckRead(tif, 1)) + return ((tsize_t) -1); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Tile out of range, max %lu", + (unsigned long) tile, (unsigned long) td->td_nstrips); + return ((tsize_t) -1); + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme does not support access to raw uncompressed data"); + return ((tsize_t) -1); + } + bytecount = td->td_stripbytecount[tile]; + if (size != (tsize_t) -1 && (uint32)size < bytecount) + bytecount = size; + return (TIFFReadRawTile1(tif, tile, buf, bytecount, module)); +} + +/* + * Read the specified tile and setup for decoding. The data buffer is + * expanded, as necessary, to hold the tile's data. + */ +int +TIFFFillTile(TIFF* tif, ttile_t tile) +{ + static const char module[] = "TIFFFillTile"; + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + /* + * FIXME: butecount should have tsize_t type, but for now + * libtiff defines tsize_t as a signed 32-bit integer and we + * are losing ability to read arrays larger than 2^31 bytes. + * So we are using uint32 instead of tsize_t here. + */ + uint32 bytecount = td->td_stripbytecount[tile]; + if (bytecount <= 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Invalid tile byte count, tile %lu", + (unsigned long) bytecount, (unsigned long) tile); + return (0); + } + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is + * going to handle this operation itself. In this + * case, avoid copying the raw data and instead just + * reference the data from the memory mapped file + * image. This assumes that the decompression + * routines do not modify the contents of the raw data + * buffer (if they try to, the application will get a + * fault since the file is mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + /* + * We must check for overflow, potentially causing + * an OOB read. Instead of simple + * + * td->td_stripoffset[tile]+bytecount > tif->tif_size + * + * comparison (which can overflow) we do the following + * two comparisons: + */ + if (bytecount > tif->tif_size || + td->td_stripoffset[tile] > tif->tif_size - bytecount) { + tif->tif_curtile = NOTILE; + return (0); + } + tif->tif_rawdatasize = bytecount; + tif->tif_rawdata = + tif->tif_base + td->td_stripoffset[tile]; + } else { + /* + * Expand raw data buffer, if needed, to hold data + * tile coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + if (bytecount > (uint32)tif->tif_rawdatasize) { + tif->tif_curtile = NOTILE; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, + module, + "%s: Data buffer too small to hold tile %ld", + tif->tif_name, + (long) tile); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, + TIFFroundup(bytecount, 1024))) + return (0); + } + if ((uint32)TIFFReadRawTile1(tif, tile, + (unsigned char *)tif->tif_rawdata, + bytecount, module) != bytecount) + return (0); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, bytecount); + } + } + return (TIFFStartTile(tif, tile)); +} + +/* + * Setup the raw data buffer in preparation for + * reading a strip of raw data. If the buffer + * is specified as zero, then a buffer of appropriate + * size is allocated by the library. Otherwise, + * the client must guarantee that the buffer is + * large enough to hold any individual strip of + * raw data. + */ +int +TIFFReadBufferSetup(TIFF* tif, tdata_t bp, tsize_t size) +{ + static const char module[] = "TIFFReadBufferSetup"; + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + } + + if (bp) { + tif->tif_rawdatasize = size; + tif->tif_rawdata = (tidata_t) bp; + tif->tif_flags &= ~TIFF_MYBUFFER; + } else { + tif->tif_rawdatasize = TIFFroundup(size, 1024); + if (tif->tif_rawdatasize > 0) + tif->tif_rawdata = (tidata_t) _TIFFmalloc(tif->tif_rawdatasize); + tif->tif_flags |= TIFF_MYBUFFER; + } + if ((tif->tif_rawdata == NULL) || (tif->tif_rawdatasize == 0)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: No space for data buffer at scanline %ld", + tif->tif_name, (long) tif->tif_row); + tif->tif_rawdatasize = 0; + return (0); + } + return (1); +} + +/* + * Set state to appear as if a + * strip has just been read in. + */ +static int +TIFFStartStrip(TIFF* tif, tstrip_t strip) +{ + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if (tif->tif_flags&TIFF_NOREADRAW) + { + tif->tif_rawcp = NULL; + tif->tif_rawcc = 0; + } + else + { + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_rawcc = td->td_stripbytecount[strip]; + } + return ((*tif->tif_predecode)(tif, + (tsample_t)(strip / td->td_stripsperimage))); +} + +/* + * Set state to appear as if a + * tile has just been read in. + */ +static int +TIFFStartTile(TIFF* tif, ttile_t tile) +{ + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curtile = tile; + tif->tif_row = + (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) * + td->td_tilelength; + tif->tif_col = + (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) * + td->td_tilewidth; + if (tif->tif_flags&TIFF_NOREADRAW) + { + tif->tif_rawcp = NULL; + tif->tif_rawcc = 0; + } + else + { + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_rawcc = td->td_stripbytecount[tile]; + } + return ((*tif->tif_predecode)(tif, + (tsample_t)(tile/td->td_stripsperimage))); +} + +static int +TIFFCheckRead(TIFF* tif, int tiles) +{ + if (tif->tif_mode == O_WRONLY) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading"); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ? + "Can not read tiles from a stripped image" : + "Can not read scanlines from a tiled image"); + return (0); + } + return (1); +} + +void +_TIFFNoPostDecode(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; (void) buf; (void) cc; +} + +void +_TIFFSwab16BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc & 1) == 0); + TIFFSwabArrayOfShort((uint16*) buf, cc/2); +} + +void +_TIFFSwab24BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc % 3) == 0); + TIFFSwabArrayOfTriples((uint8*) buf, cc/3); +} + +void +_TIFFSwab32BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc & 3) == 0); + TIFFSwabArrayOfLong((uint32*) buf, cc/4); +} + +void +_TIFFSwab64BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc & 7) == 0); + TIFFSwabArrayOfDouble((double*) buf, cc/8); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_stream.cxx b/thirdparty/libtiff/tif_stream.cxx new file mode 100644 index 00000000..2a2351b2 --- /dev/null +++ b/thirdparty/libtiff/tif_stream.cxx @@ -0,0 +1,295 @@ +/* $Id: tif_stream.cxx,v 1.6.2.1 2009-01-01 00:10:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1996 Sam Leffler + * Copyright (c) 1991-1996 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library UNIX-specific Routines. + */ +#include "tiffiop.h" +#include + +#ifndef __VMS +using namespace std; +#endif + +class tiffis_data +{ + public: + + istream *myIS; + long myStreamStartPos; +}; + +class tiffos_data +{ + public: + + ostream *myOS; + long myStreamStartPos; +}; + +static tsize_t +_tiffosReadProc(thandle_t, tdata_t, tsize_t) +{ + return 0; +} + +static tsize_t +_tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + tiffis_data *data = (tiffis_data *)fd; + + data->myIS->read((char *)buf, (int)size); + + return data->myIS->gcount(); +} + +static tsize_t +_tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + tiffos_data *data = (tiffos_data *)fd; + ostream *os = data->myOS; + int pos = os->tellp(); + + os->write((const char *)buf, size); + + return ((int)os->tellp()) - pos; +} + +static tsize_t +_tiffisWriteProc(thandle_t, tdata_t, tsize_t) +{ + return 0; +} + +static toff_t +_tiffosSeekProc(thandle_t fd, toff_t off, int whence) +{ + tiffos_data *data = (tiffos_data *)fd; + ostream *os = data->myOS; + + // if the stream has already failed, don't do anything + if( os->fail() ) + return os->tellp(); + + switch(whence) { + case SEEK_SET: + os->seekp(data->myStreamStartPos + off, ios::beg); + break; + case SEEK_CUR: + os->seekp(off, ios::cur); + break; + case SEEK_END: + os->seekp(off, ios::end); + break; + } + + // Attempt to workaround problems with seeking past the end of the + // stream. ofstream doesn't have a problem with this but + // ostrstream/ostringstream does. In that situation, add intermediate + // '\0' characters. + if( os->fail() ) { +#ifdef __VMS + int old_state; +#else + ios::iostate old_state; +#endif + toff_t origin=0; + + old_state = os->rdstate(); + // reset the fail bit or else tellp() won't work below + os->clear(os->rdstate() & ~ios::failbit); + switch( whence ) { + case SEEK_SET: + origin = data->myStreamStartPos; + break; + case SEEK_CUR: + origin = os->tellp(); + break; + case SEEK_END: + os->seekp(0, ios::end); + origin = os->tellp(); + break; + } + // restore original stream state + os->clear(old_state); + + // only do something if desired seek position is valid + if( origin + off > data->myStreamStartPos ) { + toff_t num_fill; + + // clear the fail bit + os->clear(os->rdstate() & ~ios::failbit); + + // extend the stream to the expected size + os->seekp(0, ios::end); + num_fill = origin + off - (toff_t)os->tellp(); + for( toff_t i = 0; i < num_fill; i++ ) + os->put('\0'); + + // retry the seek + os->seekp(origin + off, ios::beg); + } + } + + return os->tellp(); +} + +static toff_t +_tiffisSeekProc(thandle_t fd, toff_t off, int whence) +{ + tiffis_data *data = (tiffis_data *)fd; + + switch(whence) { + case SEEK_SET: + data->myIS->seekg(data->myStreamStartPos + off, ios::beg); + break; + case SEEK_CUR: + data->myIS->seekg(off, ios::cur); + break; + case SEEK_END: + data->myIS->seekg(off, ios::end); + break; + } + + return ((long)data->myIS->tellg()) - data->myStreamStartPos; +} + +static toff_t +_tiffosSizeProc(thandle_t fd) +{ + tiffos_data *data = (tiffos_data *)fd; + ostream *os = data->myOS; + toff_t pos = os->tellp(); + toff_t len; + + os->seekp(0, ios::end); + len = os->tellp(); + os->seekp(pos); + + return len; +} + +static toff_t +_tiffisSizeProc(thandle_t fd) +{ + tiffis_data *data = (tiffis_data *)fd; + int pos = data->myIS->tellg(); + int len; + + data->myIS->seekg(0, ios::end); + len = data->myIS->tellg(); + data->myIS->seekg(pos); + + return len; +} + +static int +_tiffosCloseProc(thandle_t fd) +{ + // Our stream was not allocated by us, so it shouldn't be closed by us. + delete (tiffos_data *)fd; + return 0; +} + +static int +_tiffisCloseProc(thandle_t fd) +{ + // Our stream was not allocated by us, so it shouldn't be closed by us. + delete (tiffis_data *)fd; + return 0; +} + +static int +_tiffDummyMapProc(thandle_t , tdata_t* , toff_t* ) +{ + return (0); +} + +static void +_tiffDummyUnmapProc(thandle_t , tdata_t , toff_t ) +{ +} + +/* + * Open a TIFF file descriptor for read/writing. + */ +static TIFF* +_tiffStreamOpen(const char* name, const char* mode, void *fd) +{ + TIFF* tif; + + if( strchr(mode, 'w') ) { + tiffos_data *data = new tiffos_data; + data->myOS = (ostream *)fd; + data->myStreamStartPos = data->myOS->tellp(); + + // Open for writing. + tif = TIFFClientOpen(name, mode, + (thandle_t) data, + _tiffosReadProc, _tiffosWriteProc, + _tiffosSeekProc, _tiffosCloseProc, + _tiffosSizeProc, + _tiffDummyMapProc, _tiffDummyUnmapProc); + } else { + tiffis_data *data = new tiffis_data; + data->myIS = (istream *)fd; + data->myStreamStartPos = data->myIS->tellg(); + // Open for reading. + tif = TIFFClientOpen(name, mode, + (thandle_t) data, + _tiffisReadProc, _tiffisWriteProc, + _tiffisSeekProc, _tiffisCloseProc, + _tiffisSizeProc, + _tiffDummyMapProc, _tiffDummyUnmapProc); + } + + return (tif); +} + +TIFF* +TIFFStreamOpen(const char* name, ostream *os) +{ + // If os is either a ostrstream or ostringstream, and has no data + // written to it yet, then tellp() will return -1 which will break us. + // We workaround this by writing out a dummy character and + // then seek back to the beginning. + if( !os->fail() && (int)os->tellp() < 0 ) { + *os << '\0'; + os->seekp(0); + } + + // NB: We don't support mapped files with streams so add 'm' + return _tiffStreamOpen(name, "wm", os); +} + +TIFF* +TIFFStreamOpen(const char* name, istream *is) +{ + // NB: We don't support mapped files with streams so add 'm' + return _tiffStreamOpen(name, "rm", is); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ diff --git a/thirdparty/libtiff/tif_strip.c b/thirdparty/libtiff/tif_strip.c new file mode 100644 index 00000000..63dec6bd --- /dev/null +++ b/thirdparty/libtiff/tif_strip.c @@ -0,0 +1,370 @@ +/* $Id: tif_strip.c,v 1.19.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Strip-organized Image Support Routines. + */ +#include "tiffiop.h" + +static uint32 +summarize(TIFF* tif, size_t summand1, size_t summand2, const char* where) +{ + /* + * XXX: We are using casting to uint32 here, bacause sizeof(size_t) + * may be larger than sizeof(uint32) on 64-bit architectures. + */ + uint32 bytes = summand1 + summand2; + + if (bytes - summand1 != summand2) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); + bytes = 0; + } + + return (bytes); +} + +static uint32 +multiply(TIFF* tif, size_t nmemb, size_t elem_size, const char* where) +{ + uint32 bytes = nmemb * elem_size; + + if (elem_size && bytes / elem_size != nmemb) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); + bytes = 0; + } + + return (bytes); +} + +/* + * Compute which strip a (row,sample) value is in. + */ +tstrip_t +TIFFComputeStrip(TIFF* tif, uint32 row, tsample_t sample) +{ + TIFFDirectory *td = &tif->tif_dir; + tstrip_t strip; + + strip = row / td->td_rowsperstrip; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return ((tstrip_t) 0); + } + strip += sample*td->td_stripsperimage; + } + return (strip); +} + +/* + * Compute how many strips are in an image. + */ +tstrip_t +TIFFNumberOfStrips(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tstrip_t nstrips; + + nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 : + TIFFhowmany(td->td_imagelength, td->td_rowsperstrip)); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + nstrips = multiply(tif, nstrips, td->td_samplesperpixel, + "TIFFNumberOfStrips"); + return (nstrips); +} + +/* + * Compute the # bytes in a variable height, row-aligned strip. + */ +tsize_t +TIFFVStripSize(TIFF* tif, uint32 nrows) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (nrows == (uint32) -1) + nrows = td->td_imagelength; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_photometric == PHOTOMETRIC_YCBCR && + !isUpSampled(tif)) { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + uint16 ycbcrsubsampling[2]; + tsize_t w, scanline, samplingarea; + + TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling + 0, + ycbcrsubsampling + 1 ); + + samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1]; + if (samplingarea == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Invalid YCbCr subsampling"); + return 0; + } + + w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]); + scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample, + "TIFFVStripSize")); + nrows = TIFFroundup(nrows, ycbcrsubsampling[1]); + /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ + scanline = multiply(tif, nrows, scanline, "TIFFVStripSize"); + return ((tsize_t) + summarize(tif, scanline, + multiply(tif, 2, scanline / samplingarea, + "TIFFVStripSize"), "TIFFVStripSize")); + } else + return ((tsize_t) multiply(tif, nrows, TIFFScanlineSize(tif), + "TIFFVStripSize")); +} + + +/* + * Compute the # bytes in a raw strip. + */ +tsize_t +TIFFRawStripSize(TIFF* tif, tstrip_t strip) +{ + TIFFDirectory* td = &tif->tif_dir; + tsize_t bytecount = td->td_stripbytecount[strip]; + + if (bytecount <= 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Invalid strip byte count, strip %lu", + (unsigned long) bytecount, (unsigned long) strip); + bytecount = (tsize_t) -1; + } + + return bytecount; +} + +/* + * Compute the # bytes in a (row-aligned) strip. + * + * Note that if RowsPerStrip is larger than the + * recorded ImageLength, then the strip size is + * truncated to reflect the actual space required + * to hold the strip. + */ +tsize_t +TIFFStripSize(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + uint32 rps = td->td_rowsperstrip; + if (rps > td->td_imagelength) + rps = td->td_imagelength; + return (TIFFVStripSize(tif, rps)); +} + +/* + * Compute a default strip size based on the image + * characteristics and a requested value. If the + * request is <1 then we choose a strip size according + * to certain heuristics. + */ +uint32 +TIFFDefaultStripSize(TIFF* tif, uint32 request) +{ + return (*tif->tif_defstripsize)(tif, request); +} + +uint32 +_TIFFDefaultStripSize(TIFF* tif, uint32 s) +{ + if ((int32) s < 1) { + /* + * If RowsPerStrip is unspecified, try to break the + * image up into strips that are approximately + * STRIP_SIZE_DEFAULT bytes long. + */ + tsize_t scanline = TIFFScanlineSize(tif); + s = (uint32)STRIP_SIZE_DEFAULT / (scanline == 0 ? 1 : scanline); + if (s == 0) /* very wide images */ + s = 1; + } + return (s); +} + +/* + * Return the number of bytes to read/write in a call to + * one of the scanline-oriented i/o routines. Note that + * this number may be 1/samples-per-pixel if data is + * stored as separate planes. + */ +tsize_t +TIFFScanlineSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t scanline; + + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR + && !isUpSampled(tif)) { + uint16 ycbcrsubsampling[2]; + + TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling + 0, + ycbcrsubsampling + 1); + + if (ycbcrsubsampling[0] == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Invalid YCbCr subsampling"); + return 0; + } + + scanline = TIFFroundup(td->td_imagewidth, + ycbcrsubsampling[0]); + scanline = TIFFhowmany8(multiply(tif, scanline, + td->td_bitspersample, + "TIFFScanlineSize")); + return ((tsize_t) + summarize(tif, scanline, + multiply(tif, 2, + scanline / ycbcrsubsampling[0], + "TIFFVStripSize"), + "TIFFVStripSize")); + } else { + scanline = multiply(tif, td->td_imagewidth, + td->td_samplesperpixel, + "TIFFScanlineSize"); + } + } else + scanline = td->td_imagewidth; + return ((tsize_t) TIFFhowmany8(multiply(tif, scanline, + td->td_bitspersample, + "TIFFScanlineSize"))); +} + +/* + * Some stuff depends on this older version of TIFFScanlineSize + * TODO: resolve this + */ +tsize_t +TIFFOldScanlineSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t scanline; + + scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth, + "TIFFScanlineSize"); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + scanline = multiply (tif, scanline, td->td_samplesperpixel, + "TIFFScanlineSize"); + return ((tsize_t) TIFFhowmany8(scanline)); +} + +/* + * Return the number of bytes to read/write in a call to + * one of the scanline-oriented i/o routines. Note that + * this number may be 1/samples-per-pixel if data is + * stored as separate planes. + * The ScanlineSize in case of YCbCrSubsampling is defined as the + * strip size divided by the strip height, i.e. the size of a pack of vertical + * subsampling lines divided by vertical subsampling. It should thus make + * sense when multiplied by a multiple of vertical subsampling. + * Some stuff depends on this newer version of TIFFScanlineSize + * TODO: resolve this + */ +tsize_t +TIFFNewScanlineSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t scanline; + + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR + && !isUpSampled(tif)) { + uint16 ycbcrsubsampling[2]; + + TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling + 0, + ycbcrsubsampling + 1); + + if (ycbcrsubsampling[0]*ycbcrsubsampling[1] == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Invalid YCbCr subsampling"); + return 0; + } + + return((tsize_t) ((((td->td_imagewidth+ycbcrsubsampling[0]-1) + /ycbcrsubsampling[0]) + *(ycbcrsubsampling[0]*ycbcrsubsampling[1]+2) + *td->td_bitspersample+7) + /8)/ycbcrsubsampling[1]); + + } else { + scanline = multiply(tif, td->td_imagewidth, + td->td_samplesperpixel, + "TIFFScanlineSize"); + } + } else + scanline = td->td_imagewidth; + return ((tsize_t) TIFFhowmany8(multiply(tif, scanline, + td->td_bitspersample, + "TIFFScanlineSize"))); +} + +/* + * Return the number of bytes required to store a complete + * decoded and packed raster scanline (as opposed to the + * I/O size returned by TIFFScanlineSize which may be less + * if data is store as separate planes). + */ +tsize_t +TIFFRasterScanlineSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t scanline; + + scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth, + "TIFFRasterScanlineSize"); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + scanline = multiply (tif, scanline, td->td_samplesperpixel, + "TIFFRasterScanlineSize"); + return ((tsize_t) TIFFhowmany8(scanline)); + } else + return ((tsize_t) multiply (tif, TIFFhowmany8(scanline), + td->td_samplesperpixel, + "TIFFRasterScanlineSize")); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_swab.c b/thirdparty/libtiff/tif_swab.c new file mode 100644 index 00000000..e4f1a6d1 --- /dev/null +++ b/thirdparty/libtiff/tif_swab.c @@ -0,0 +1,242 @@ +/* $Id: tif_swab.c,v 1.4.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Bit & Byte Swapping Support. + * + * XXX We assume short = 16-bits and long = 32-bits XXX + */ +#include "tiffiop.h" + +#ifndef TIFFSwabShort +void +TIFFSwabShort(uint16* wp) +{ + register unsigned char* cp = (unsigned char*) wp; + unsigned char t; + + t = cp[1]; cp[1] = cp[0]; cp[0] = t; +} +#endif + +#ifndef TIFFSwabLong +void +TIFFSwabLong(uint32* lp) +{ + register unsigned char* cp = (unsigned char*) lp; + unsigned char t; + + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} +#endif + +#ifndef TIFFSwabArrayOfShort +void +TIFFSwabArrayOfShort(uint16* wp, register unsigned long n) +{ + register unsigned char* cp; + register unsigned char t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char*) wp; + t = cp[1]; cp[1] = cp[0]; cp[0] = t; + wp++; + } +} +#endif + +#ifndef TIFFSwabArrayOfTriples +void +TIFFSwabArrayOfTriples(uint8* tp, unsigned long n) +{ + unsigned char* cp; + unsigned char t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char*) tp; + t = cp[2]; cp[2] = cp[0]; cp[0] = t; + tp += 3; + } +} +#endif + +#ifndef TIFFSwabArrayOfLong +void +TIFFSwabArrayOfLong(register uint32* lp, register unsigned long n) +{ + register unsigned char *cp; + register unsigned char t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)lp; + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; + lp++; + } +} +#endif + +#ifndef TIFFSwabDouble +void +TIFFSwabDouble(double *dp) +{ + register uint32* lp = (uint32*) dp; + uint32 t; + + TIFFSwabArrayOfLong(lp, 2); + t = lp[0]; lp[0] = lp[1]; lp[1] = t; +} +#endif + +#ifndef TIFFSwabArrayOfDouble +void +TIFFSwabArrayOfDouble(double* dp, register unsigned long n) +{ + register uint32* lp = (uint32*) dp; + register uint32 t; + + TIFFSwabArrayOfLong(lp, n + n); + while (n-- > 0) { + t = lp[0]; lp[0] = lp[1]; lp[1] = t; + lp += 2; + } +} +#endif + +/* + * Bit reversal tables. TIFFBitRevTable[] gives + * the bit reversed value of . Used in various + * places in the library when the FillOrder requires + * bit reversal of byte values (e.g. CCITT Fax 3 + * encoding/decoding). TIFFNoBitRevTable is provided + * for algorithms that want an equivalent table that + * do not reverse bit values. + */ +static const unsigned char TIFFBitRevTable[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; +static const unsigned char TIFFNoBitRevTable[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +const unsigned char* +TIFFGetBitRevTable(int reversed) +{ + return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable); +} + +void +TIFFReverseBits(register unsigned char* cp, register unsigned long n) +{ + for (; n > 8; n -= 8) { + cp[0] = TIFFBitRevTable[cp[0]]; + cp[1] = TIFFBitRevTable[cp[1]]; + cp[2] = TIFFBitRevTable[cp[2]]; + cp[3] = TIFFBitRevTable[cp[3]]; + cp[4] = TIFFBitRevTable[cp[4]]; + cp[5] = TIFFBitRevTable[cp[5]]; + cp[6] = TIFFBitRevTable[cp[6]]; + cp[7] = TIFFBitRevTable[cp[7]]; + cp += 8; + } + while (n-- > 0) + *cp = TIFFBitRevTable[*cp], cp++; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_thunder.c b/thirdparty/libtiff/tif_thunder.c new file mode 100644 index 00000000..8e7a1258 --- /dev/null +++ b/thirdparty/libtiff/tif_thunder.c @@ -0,0 +1,165 @@ +/* $Id: tif_thunder.c,v 1.5.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef THUNDER_SUPPORT +/* + * TIFF Library. + * + * ThunderScan 4-bit Compression Algorithm Support + */ + +/* + * ThunderScan uses an encoding scheme designed for + * 4-bit pixel values. Data is encoded in bytes, with + * each byte split into a 2-bit code word and a 6-bit + * data value. The encoding gives raw data, runs of + * pixels, or pixel values encoded as a delta from the + * previous pixel value. For the latter, either 2-bit + * or 3-bit delta values are used, with the deltas packed + * into a single byte. + */ +#define THUNDER_DATA 0x3f /* mask for 6-bit data */ +#define THUNDER_CODE 0xc0 /* mask for 2-bit code word */ +/* code values */ +#define THUNDER_RUN 0x00 /* run of pixels w/ encoded count */ +#define THUNDER_2BITDELTAS 0x40 /* 3 pixels w/ encoded 2-bit deltas */ +#define DELTA2_SKIP 2 /* skip code for 2-bit deltas */ +#define THUNDER_3BITDELTAS 0x80 /* 2 pixels w/ encoded 3-bit deltas */ +#define DELTA3_SKIP 4 /* skip code for 3-bit deltas */ +#define THUNDER_RAW 0xc0 /* raw data encoded */ + +static const int twobitdeltas[4] = { 0, 1, 0, -1 }; +static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 }; + +#define SETPIXEL(op, v) { \ + lastpixel = (v) & 0xf; \ + if (npixels++ & 1) \ + *op++ |= lastpixel; \ + else \ + op[0] = (tidataval_t) (lastpixel << 4); \ +} + +static int +ThunderDecode(TIFF* tif, tidata_t op, tsize_t maxpixels) +{ + register unsigned char *bp; + register tsize_t cc; + unsigned int lastpixel; + tsize_t npixels; + + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + lastpixel = 0; + npixels = 0; + while (cc > 0 && npixels < maxpixels) { + int n, delta; + + n = *bp++, cc--; + switch (n & THUNDER_CODE) { + case THUNDER_RUN: /* pixel run */ + /* + * Replicate the last pixel n times, + * where n is the lower-order 6 bits. + */ + if (npixels & 1) { + op[0] |= lastpixel; + lastpixel = *op++; npixels++; n--; + } else + lastpixel |= lastpixel << 4; + npixels += n; + if (npixels < maxpixels) { + for (; n > 0; n -= 2) + *op++ = (tidataval_t) lastpixel; + } + if (n == -1) + *--op &= 0xf0; + lastpixel &= 0xf; + break; + case THUNDER_2BITDELTAS: /* 2-bit deltas */ + if ((delta = ((n >> 4) & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + if ((delta = (n & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + break; + case THUNDER_3BITDELTAS: /* 3-bit deltas */ + if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP) + SETPIXEL(op, lastpixel + threebitdeltas[delta]); + if ((delta = (n & 7)) != DELTA3_SKIP) + SETPIXEL(op, lastpixel + threebitdeltas[delta]); + break; + case THUNDER_RAW: /* raw data */ + SETPIXEL(op, n); + break; + } + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + if (npixels != maxpixels) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "ThunderDecode: %s data at scanline %ld (%lu != %lu)", + npixels < maxpixels ? "Not enough" : "Too much", + (long) tif->tif_row, (long) npixels, (long) maxpixels); + return (0); + } + return (1); +} + +static int +ThunderDecodeRow(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + tidata_t row = buf; + + (void) s; + while ((long)occ > 0) { + if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth)) + return (0); + occ -= tif->tif_scanlinesize; + row += tif->tif_scanlinesize; + } + return (1); +} + +int +TIFFInitThunderScan(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = ThunderDecodeRow; + tif->tif_decodestrip = ThunderDecodeRow; + return (1); +} +#endif /* THUNDER_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_tile.c b/thirdparty/libtiff/tif_tile.c new file mode 100644 index 00000000..d8379e61 --- /dev/null +++ b/thirdparty/libtiff/tif_tile.c @@ -0,0 +1,280 @@ +/* $Id: tif_tile.c,v 1.12.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Tiled Image Support Routines. + */ +#include "tiffiop.h" + +static uint32 +summarize(TIFF* tif, size_t summand1, size_t summand2, const char* where) +{ + /* + * XXX: We are using casting to uint32 here, because sizeof(size_t) + * may be larger than sizeof(uint32) on 64-bit architectures. + */ + uint32 bytes = summand1 + summand2; + + if (bytes - summand1 != summand2) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); + bytes = 0; + } + + return (bytes); +} + +static uint32 +multiply(TIFF* tif, size_t nmemb, size_t elem_size, const char* where) +{ + uint32 bytes = nmemb * elem_size; + + if (elem_size && bytes / elem_size != nmemb) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); + bytes = 0; + } + + return (bytes); +} + +/* + * Compute which tile an (x,y,z,s) value is in. + */ +ttile_t +TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 dx = td->td_tilewidth; + uint32 dy = td->td_tilelength; + uint32 dz = td->td_tiledepth; + ttile_t tile = 1; + + if (td->td_imagedepth == 1) + z = 0; + if (dx == (uint32) -1) + dx = td->td_imagewidth; + if (dy == (uint32) -1) + dy = td->td_imagelength; + if (dz == (uint32) -1) + dz = td->td_imagedepth; + if (dx != 0 && dy != 0 && dz != 0) { + uint32 xpt = TIFFhowmany(td->td_imagewidth, dx); + uint32 ypt = TIFFhowmany(td->td_imagelength, dy); + uint32 zpt = TIFFhowmany(td->td_imagedepth, dz); + + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + tile = (xpt*ypt*zpt)*s + + (xpt*ypt)*(z/dz) + + xpt*(y/dy) + + x/dx; + else + tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx; + } + return (tile); +} + +/* + * Check an (x,y,z,s) coordinate + * against the image bounds. + */ +int +TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (x >= td->td_imagewidth) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Col out of range, max %lu", + (unsigned long) x, + (unsigned long) (td->td_imagewidth - 1)); + return (0); + } + if (y >= td->td_imagelength) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Row out of range, max %lu", + (unsigned long) y, + (unsigned long) (td->td_imagelength - 1)); + return (0); + } + if (z >= td->td_imagedepth) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Depth out of range, max %lu", + (unsigned long) z, + (unsigned long) (td->td_imagedepth - 1)); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && + s >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Sample out of range, max %lu", + (unsigned long) s, + (unsigned long) (td->td_samplesperpixel - 1)); + return (0); + } + return (1); +} + +/* + * Compute how many tiles are in an image. + */ +ttile_t +TIFFNumberOfTiles(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 dx = td->td_tilewidth; + uint32 dy = td->td_tilelength; + uint32 dz = td->td_tiledepth; + ttile_t ntiles; + + if (dx == (uint32) -1) + dx = td->td_imagewidth; + if (dy == (uint32) -1) + dy = td->td_imagelength; + if (dz == (uint32) -1) + dz = td->td_imagedepth; + ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 : + multiply(tif, multiply(tif, TIFFhowmany(td->td_imagewidth, dx), + TIFFhowmany(td->td_imagelength, dy), + "TIFFNumberOfTiles"), + TIFFhowmany(td->td_imagedepth, dz), "TIFFNumberOfTiles"); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + ntiles = multiply(tif, ntiles, td->td_samplesperpixel, + "TIFFNumberOfTiles"); + return (ntiles); +} + +/* + * Compute the # bytes in each row of a tile. + */ +tsize_t +TIFFTileRowSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t rowsize; + + if (td->td_tilelength == 0 || td->td_tilewidth == 0) + return ((tsize_t) 0); + rowsize = multiply(tif, td->td_bitspersample, td->td_tilewidth, + "TIFFTileRowSize"); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + rowsize = multiply(tif, rowsize, td->td_samplesperpixel, + "TIFFTileRowSize"); + return ((tsize_t) TIFFhowmany8(rowsize)); +} + +/* + * Compute the # bytes in a variable length, row-aligned tile. + */ +tsize_t +TIFFVTileSize(TIFF* tif, uint32 nrows) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t tilesize; + + if (td->td_tilelength == 0 || td->td_tilewidth == 0 || + td->td_tiledepth == 0) + return ((tsize_t) 0); + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_photometric == PHOTOMETRIC_YCBCR && + !isUpSampled(tif)) { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + tsize_t w = + TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]); + tsize_t rowsize = + TIFFhowmany8(multiply(tif, w, td->td_bitspersample, + "TIFFVTileSize")); + tsize_t samplingarea = + td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; + if (samplingarea == 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); + return 0; + } + nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); + /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ + tilesize = multiply(tif, nrows, rowsize, "TIFFVTileSize"); + tilesize = summarize(tif, tilesize, + multiply(tif, 2, tilesize / samplingarea, + "TIFFVTileSize"), + "TIFFVTileSize"); + } else + tilesize = multiply(tif, nrows, TIFFTileRowSize(tif), + "TIFFVTileSize"); + return ((tsize_t) + multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize")); +} + +/* + * Compute the # bytes in a row-aligned tile. + */ +tsize_t +TIFFTileSize(TIFF* tif) +{ + return (TIFFVTileSize(tif, tif->tif_dir.td_tilelength)); +} + +/* + * Compute a default tile size based on the image + * characteristics and a requested value. If a + * request is <1 then we choose a size according + * to certain heuristics. + */ +void +TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + (*tif->tif_deftilesize)(tif, tw, th); +} + +void +_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + (void) tif; + if (*(int32*) tw < 1) + *tw = 256; + if (*(int32*) th < 1) + *th = 256; + /* roundup to a multiple of 16 per the spec */ + if (*tw & 0xf) + *tw = TIFFroundup(*tw, 16); + if (*th & 0xf) + *th = TIFFroundup(*th, 16); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_unix.c b/thirdparty/libtiff/tif_unix.c new file mode 100644 index 00000000..e0f1a8dd --- /dev/null +++ b/thirdparty/libtiff/tif_unix.c @@ -0,0 +1,296 @@ +/* $Id: tif_unix.c,v 1.12.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library UNIX-specific Routines. These are should also work with the + * Windows Common RunTime Library. + */ +#include "tif_config.h" + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#include "tiffiop.h" + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return ((tsize_t) read((int) fd, buf, (size_t) size)); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return ((tsize_t) write((int) fd, buf, (size_t) size)); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + return ((toff_t) lseek((int) fd, (off_t) off, whence)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (close((int) fd)); +} + + +static toff_t +_tiffSizeProc(thandle_t fd) +{ +#ifdef _AM29K + long fsize; + return ((fsize = lseek((int) fd, 0, SEEK_END)) < 0 ? 0 : fsize); +#else + struct stat sb; + return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size); +#endif +} + +#ifdef HAVE_MMAP +#include + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + toff_t size = _tiffSizeProc(fd); + if (size != (toff_t) -1) { + *pbase = (tdata_t) + mmap(0, size, PROT_READ, MAP_SHARED, (int) fd, 0); + if (*pbase != (tdata_t) -1) { + *psize = size; + return (1); + } + } + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; + (void) munmap(base, (off_t) size); +} +#else /* !HAVE_MMAP */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + (void) fd; (void) pbase; (void) psize; + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; (void) base; (void) size; +} +#endif /* !HAVE_MMAP */ + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m, fd; + TIFF* tif; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + +/* for cygwin and mingw */ +#ifdef O_BINARY + m |= O_BINARY; +#endif + +#ifdef _AM29K + fd = open(name, m); +#else + fd = open(name, m, 0666); +#endif + if (fd < 0) { + TIFFErrorExt(0, module, "%s: Cannot open", name); + return ((TIFF *)0); + } + + tif = TIFFFdOpen((int)fd, name, mode); + if(!tif) + close(fd); + return tif; +} + +#ifdef __WIN32__ +#include +/* + * Open a TIFF file with a Unicode filename, for read/writing. + */ +TIFF* +TIFFOpenW(const wchar_t* name, const char* mode) +{ + static const char module[] = "TIFFOpenW"; + int m, fd; + int mbsize; + char *mbname; + TIFF* tif; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + +/* for cygwin and mingw */ +#ifdef O_BINARY + m |= O_BINARY; +#endif + + fd = _wopen(name, m, 0666); + if (fd < 0) { + TIFFErrorExt(0, module, "%s: Cannot open", name); + return ((TIFF *)0); + } + + mbname = NULL; + mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL); + if (mbsize > 0) { + mbname = _TIFFmalloc(mbsize); + if (!mbname) { + TIFFErrorExt(0, module, + "Can't allocate space for filename conversion buffer"); + return ((TIFF*)0); + } + + WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize, + NULL, NULL); + } + + tif = TIFFFdOpen((int)fd, (mbname != NULL) ? mbname : "", + mode); + + _TIFFfree(mbname); + + if(!tif) + close(fd); + return tif; +} +#endif + +void* +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +void* +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +static void +unixWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = unixWarningHandler; + +static void +unixErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = unixErrorHandler; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_version.c b/thirdparty/libtiff/tif_version.c new file mode 100644 index 00000000..218dab56 --- /dev/null +++ b/thirdparty/libtiff/tif_version.c @@ -0,0 +1,40 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_version.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ +/* + * Copyright (c) 1992-1997 Sam Leffler + * Copyright (c) 1992-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#include "tiffiop.h" + +static const char TIFFVersion[] = TIFFLIB_VERSION_STR; + +const char* +TIFFGetVersion(void) +{ + return (TIFFVersion); +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_warning.c b/thirdparty/libtiff/tif_warning.c new file mode 100644 index 00000000..fe974d90 --- /dev/null +++ b/thirdparty/libtiff/tif_warning.c @@ -0,0 +1,81 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_warning.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL; + +TIFFErrorHandler +TIFFSetWarningHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFwarningHandler; + _TIFFwarningHandler = handler; + return (prev); +} + +TIFFErrorHandlerExt +TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler) +{ + TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt; + _TIFFwarningHandlerExt = handler; + return (prev); +} + +void +TIFFWarning(const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFwarningHandler) + (*_TIFFwarningHandler)(module, fmt, ap); + if (_TIFFwarningHandlerExt) + (*_TIFFwarningHandlerExt)(0, module, fmt, ap); + va_end(ap); +} + +void +TIFFWarningExt(thandle_t fd, const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFwarningHandler) + (*_TIFFwarningHandler)(module, fmt, ap); + if (_TIFFwarningHandlerExt) + (*_TIFFwarningHandlerExt)(fd, module, fmt, ap); + va_end(ap); +} + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_win32.c b/thirdparty/libtiff/tif_win32.c new file mode 100644 index 00000000..2ab944b1 --- /dev/null +++ b/thirdparty/libtiff/tif_win32.c @@ -0,0 +1,408 @@ +/* $Id: tif_win32.c,v 1.21.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Win32-specific Routines. Adapted from tif_unix.c 4/5/95 by + * Scott Wagner (wagner@itek.com), Itek Graphix, Rochester, NY USA + */ +#include "tiffiop.h" + +#include + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + DWORD dwSizeRead; + if (!ReadFile(fd, buf, size, &dwSizeRead, NULL)) + return(0); + return ((tsize_t) dwSizeRead); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + DWORD dwSizeWritten; + if (!WriteFile(fd, buf, size, &dwSizeWritten, NULL)) + return(0); + return ((tsize_t) dwSizeWritten); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + ULARGE_INTEGER li; + DWORD dwMoveMethod; + + li.QuadPart = off; + + switch(whence) + { + case SEEK_SET: + dwMoveMethod = FILE_BEGIN; + break; + case SEEK_CUR: + dwMoveMethod = FILE_CURRENT; + break; + case SEEK_END: + dwMoveMethod = FILE_END; + break; + default: + dwMoveMethod = FILE_BEGIN; + break; + } + return ((toff_t)SetFilePointer(fd, (LONG) li.LowPart, + (PLONG)&li.HighPart, dwMoveMethod)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (CloseHandle(fd) ? 0 : -1); +} + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + return ((toff_t)GetFileSize(fd, NULL)); +} + +static int +_tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + (void) fd; + (void) pbase; + (void) psize; + return (0); +} + +/* + * From "Hermann Josef Hill" : + * + * Windows uses both a handle and a pointer for file mapping, + * but according to the SDK documentation and Richter's book + * "Advanced Windows Programming" it is safe to free the handle + * after obtaining the file mapping pointer + * + * This removes a nasty OS dependency and cures a problem + * with Visual C++ 5.0 + */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + toff_t size; + HANDLE hMapFile; + + if ((size = _tiffSizeProc(fd)) == 0xFFFFFFFF) + return (0); + hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL); + if (hMapFile == NULL) + return (0); + *pbase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); + CloseHandle(hMapFile); + if (*pbase == NULL) + return (0); + *psize = size; + return(1); +} + +static void +_tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; + (void) base; + (void) size; +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + UnmapViewOfFile(base); +} + +/* + * Open a TIFF file descriptor for read/writing. + * Note that TIFFFdOpen and TIFFOpen recognise the character 'u' in the mode + * string, which forces the file to be opened unmapped. + */ +TIFF* +TIFFFdOpen(int ifd, const char* name, const char* mode) +{ + TIFF* tif; + BOOL fSuppressMap = (mode[1] == 'u' || (mode[1]!=0 && mode[2] == 'u')); + + tif = TIFFClientOpen(name, mode, (thandle_t)ifd, + _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + fSuppressMap ? _tiffDummyMapProc : _tiffMapProc, + fSuppressMap ? _tiffDummyUnmapProc : _tiffUnmapProc); + if (tif) + tif->tif_fd = ifd; + return (tif); +} + +#ifndef _WIN32_WCE + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + thandle_t fd; + int m; + DWORD dwMode; + TIFF* tif; + + m = _TIFFgetMode(mode, module); + + switch(m) + { + case O_RDONLY: + dwMode = OPEN_EXISTING; + break; + case O_RDWR: + dwMode = OPEN_ALWAYS; + break; + case O_RDWR|O_CREAT: + dwMode = OPEN_ALWAYS; + break; + case O_RDWR|O_TRUNC: + dwMode = CREATE_ALWAYS; + break; + case O_RDWR|O_CREAT|O_TRUNC: + dwMode = CREATE_ALWAYS; + break; + default: + return ((TIFF*)0); + } + fd = (thandle_t)CreateFileA(name, + (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode, + (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL, + NULL); + if (fd == INVALID_HANDLE_VALUE) { + TIFFErrorExt(0, module, "%s: Cannot open", name); + return ((TIFF *)0); + } + + tif = TIFFFdOpen((int)fd, name, mode); + if(!tif) + CloseHandle(fd); + return tif; +} + +/* + * Open a TIFF file with a Unicode filename, for read/writing. + */ +TIFF* +TIFFOpenW(const wchar_t* name, const char* mode) +{ + static const char module[] = "TIFFOpenW"; + thandle_t fd; + int m; + DWORD dwMode; + int mbsize; + char *mbname; + TIFF *tif; + + m = _TIFFgetMode(mode, module); + + switch(m) { + case O_RDONLY: dwMode = OPEN_EXISTING; break; + case O_RDWR: dwMode = OPEN_ALWAYS; break; + case O_RDWR|O_CREAT: dwMode = OPEN_ALWAYS; break; + case O_RDWR|O_TRUNC: dwMode = CREATE_ALWAYS; break; + case O_RDWR|O_CREAT|O_TRUNC: dwMode = CREATE_ALWAYS; break; + default: return ((TIFF*)0); + } + + fd = (thandle_t)CreateFileW(name, + (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ|GENERIC_WRITE), + FILE_SHARE_READ, NULL, dwMode, + (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL, + NULL); + if (fd == INVALID_HANDLE_VALUE) { + TIFFErrorExt(0, module, "%S: Cannot open", name); + return ((TIFF *)0); + } + + mbname = NULL; + mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL); + if (mbsize > 0) { + mbname = (char *)_TIFFmalloc(mbsize); + if (!mbname) { + TIFFErrorExt(0, module, + "Can't allocate space for filename conversion buffer"); + return ((TIFF*)0); + } + + WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize, + NULL, NULL); + } + + tif = TIFFFdOpen((int)fd, + (mbname != NULL) ? mbname : "", mode); + if(!tif) + CloseHandle(fd); + + _TIFFfree(mbname); + + return tif; +} + +#endif /* ndef _WIN32_WCE */ + + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return ((tdata_t)GlobalAlloc(GMEM_FIXED, s)); +} + +void +_TIFFfree(tdata_t p) +{ + GlobalFree(p); + return; +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + void* pvTmp; + tsize_t old; + + if(p == NULL) + return ((tdata_t)GlobalAlloc(GMEM_FIXED, s)); + + old = GlobalSize(p); + + if (old>=s) { + if ((pvTmp = GlobalAlloc(GMEM_FIXED, s)) != NULL) { + CopyMemory(pvTmp, p, s); + GlobalFree(p); + } + } else { + if ((pvTmp = GlobalAlloc(GMEM_FIXED, s)) != NULL) { + CopyMemory(pvTmp, p, old); + GlobalFree(p); + } + } + return ((tdata_t)pvTmp); +} + +void +_TIFFmemset(void* p, int v, tsize_t c) +{ + FillMemory(p, c, (BYTE)v); +} + +void +_TIFFmemcpy(void* d, const tdata_t s, tsize_t c) +{ + CopyMemory(d, s, c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + register const BYTE *pb1 = (const BYTE *) p1; + register const BYTE *pb2 = (const BYTE *) p2; + register DWORD dwTmp = c; + register int iTmp; + for (iTmp = 0; dwTmp-- && !iTmp; iTmp = (int)*pb1++ - (int)*pb2++) + ; + return (iTmp); +} + +#ifndef _WIN32_WCE + +static void +Win32WarningHandler(const char* module, const char* fmt, va_list ap) +{ +#ifndef TIF_PLATFORM_CONSOLE + LPTSTR szTitle; + LPTSTR szTmp; + LPCTSTR szTitleText = "%s Warning"; + LPCTSTR szDefaultModule = "LIBTIFF"; + LPCTSTR szTmpModule = (module == NULL) ? szDefaultModule : module; + if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmpModule) + + strlen(szTitleText) + strlen(fmt) + 128)*sizeof(char))) == NULL) + return; + sprintf(szTitle, szTitleText, szTmpModule); + szTmp = szTitle + (strlen(szTitle)+2)*sizeof(char); + vsprintf(szTmp, fmt, ap); + MessageBoxA(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION); + LocalFree(szTitle); + return; +#else + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +#endif +} +TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler; + +static void +Win32ErrorHandler(const char* module, const char* fmt, va_list ap) +{ +#ifndef TIF_PLATFORM_CONSOLE + LPTSTR szTitle; + LPTSTR szTmp; + LPCTSTR szTitleText = "%s Error"; + LPCTSTR szDefaultModule = "LIBTIFF"; + LPCTSTR szTmpModule = (module == NULL) ? szDefaultModule : module; + if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmpModule) + + strlen(szTitleText) + strlen(fmt) + 128)*sizeof(char))) == NULL) + return; + sprintf(szTitle, szTitleText, szTmpModule); + szTmp = szTitle + (strlen(szTitle)+2)*sizeof(char); + vsprintf(szTmp, fmt, ap); + MessageBoxA(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION); + LocalFree(szTitle); + return; +#else + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +#endif +} +TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler; + +#endif /* ndef _WIN32_WCE */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_write.c b/thirdparty/libtiff/tif_write.c new file mode 100644 index 00000000..bd084181 --- /dev/null +++ b/thirdparty/libtiff/tif_write.c @@ -0,0 +1,718 @@ +/* $Id: tif_write.c,v 1.22.2.5 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Scanline-oriented Write Support + */ +#include "tiffiop.h" +#include + +#define STRIPINCR 20 /* expansion factor on strip array */ + +#define WRITECHECKSTRIPS(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module)) +#define WRITECHECKTILES(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module)) +#define BUFFERCHECK(tif) \ + ((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) || \ + TIFFWriteBufferSetup((tif), NULL, (tsize_t) -1)) + +static int TIFFGrowStrips(TIFF*, int, const char*); +static int TIFFAppendToStrip(TIFF*, tstrip_t, tidata_t, tsize_t); + +int +TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) +{ + static const char module[] = "TIFFWriteScanline"; + register TIFFDirectory *td; + int status, imagegrew = 0; + tstrip_t strip; + + if (!WRITECHECKSTRIPS(tif, module)) + return (-1); + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return (-1); + td = &tif->tif_dir; + /* + * Extend image length if needed + * (but only for PlanarConfig=1). + */ + if (row >= td->td_imagelength) { /* extend image */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Can not change \"ImageLength\" when using separate planes"); + return (-1); + } + td->td_imagelength = row+1; + imagegrew = 1; + } + /* + * Calculate strip and check for crossings. + */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%d: Sample out of range, max %d", + sample, td->td_samplesperpixel); + return (-1); + } + strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + /* + * Check strip array to make sure there's space. We don't support + * dynamically growing files that have data organized in separate + * bitplanes because it's too painful. In that case we require that + * the imagelength be set properly before the first write (so that the + * strips array will be fully allocated above). + */ + if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module)) + return (-1); + if (strip != tif->tif_curstrip) { + /* + * Changing strips -- flush any data present. + */ + if (!TIFFFlushData(tif)) + return (-1); + tif->tif_curstrip = strip; + /* + * Watch out for a growing image. The value of strips/image + * will initially be 1 (since it can't be deduced until the + * imagelength is known). + */ + if (strip >= td->td_stripsperimage && imagegrew) + td->td_stripsperimage = + TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); + tif->tif_row = + (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return (-1); + tif->tif_flags |= TIFF_CODERSETUP; + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount[strip] > 0 ) + { + /* if we are writing over existing tiles, zero length */ + td->td_stripbytecount[strip] = 0; + + /* this forces TIFFAppendToStrip() to do a seek */ + tif->tif_curoff = 0; + } + + if (!(*tif->tif_preencode)(tif, sample)) + return (-1); + tif->tif_flags |= TIFF_POSTENCODE; + } + /* + * Ensure the write is either sequential or at the + * beginning of a strip (or that we can randomly + * access the data -- i.e. no encoding). + */ + if (row != tif->tif_row) { + if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: + * backup to the start and then decode + * forward (below). + */ + tif->tif_row = (strip % td->td_stripsperimage) * + td->td_rowsperstrip; + tif->tif_rawcp = tif->tif_rawdata; + } + /* + * Seek forward to the desired row. + */ + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (-1); + tif->tif_row = row; + } + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode( tif, (tidata_t) buf, tif->tif_scanlinesize ); + + status = (*tif->tif_encoderow)(tif, (tidata_t) buf, + tif->tif_scanlinesize, sample); + + /* we are now poised at the beginning of the next row */ + tif->tif_row = row + 1; + return (status); +} + +/* + * Encode the supplied data and write it to the + * specified strip. + * + * NB: Image length must be setup before writing. + */ +tsize_t +TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + tsample_t sample; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Can not grow image by strips when using separate planes"); + return ((tsize_t) -1); + } + if (!TIFFGrowStrips(tif, 1, module)) + return ((tsize_t) -1); + td->td_stripsperimage = + TIFFhowmany(td->td_imagelength, td->td_rowsperstrip); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized according to the directory + * info. + */ + if (!BUFFERCHECK(tif)) + return ((tsize_t) -1); + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tsize_t) -1); + tif->tif_flags |= TIFF_CODERSETUP; + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount[strip] > 0 ) + { + /* Force TIFFAppendToStrip() to consider placing data at end + of file. */ + tif->tif_curoff = 0; + } + + tif->tif_flags &= ~TIFF_POSTENCODE; + sample = (tsample_t)(strip / td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tsize_t) -1); + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode( tif, (tidata_t) data, cc ); + + if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample)) + return ((tsize_t) 0); + if (!(*tif->tif_postencode)(tif)) + return ((tsize_t) -1); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && + !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc)) + return ((tsize_t) -1); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * + * NB: Image length must be setup before writing. + */ +tsize_t +TIFFWriteRawStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Can not grow image by strips when using separate planes"); + return ((tsize_t) -1); + } + /* + * Watch out for a growing image. The value of + * strips/image will initially be 1 (since it + * can't be deduced until the imagelength is known). + */ + if (strip >= td->td_stripsperimage) + td->td_stripsperimage = + TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); + if (!TIFFGrowStrips(tif, 1, module)) + return ((tsize_t) -1); + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + return (TIFFAppendToStrip(tif, strip, (tidata_t) data, cc) ? + cc : (tsize_t) -1); +} + +/* + * Write and compress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tsize_t +TIFFWriteTile(TIFF* tif, + tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + if (!TIFFCheckTile(tif, x, y, z, s)) + return (-1); + /* + * NB: A tile size of -1 is used instead of tif_tilesize knowing + * that TIFFWriteEncodedTile will clamp this to the tile size. + * This is done because the tile size may not be defined until + * after the output buffer is setup in TIFFWriteBufferSetup. + */ + return (TIFFWriteEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1)); +} + +/* + * Encode the supplied data and write it to the + * specified tile. There must be space for the + * data. The function clamps individual writes + * to a tile to the tile size, but does not (and + * can not) check that multiple writes to the same + * tile do not write more than tile size data. + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tsize_t +TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedTile"; + TIFFDirectory *td; + tsample_t sample; + + if (!WRITECHECKTILES(tif, module)) + return ((tsize_t) -1); + td = &tif->tif_dir; + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu", + tif->tif_name, (unsigned long) tile, (unsigned long) td->td_nstrips); + return ((tsize_t) -1); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return ((tsize_t) -1); + tif->tif_curtile = tile; + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount[tile] > 0 ) + { + /* Force TIFFAppendToStrip() to consider placing data at end + of file. */ + tif->tif_curoff = 0; + } + + /* + * Compute tiles per row & per column to compute + * current row and column + */ + tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) + * td->td_tilelength; + tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) + * td->td_tilewidth; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tsize_t) -1); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_flags &= ~TIFF_POSTENCODE; + sample = (tsample_t)(tile/td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tsize_t) -1); + /* + * Clamp write amount to the tile size. This is mostly + * done so that callers can pass in some large number + * (e.g. -1) and have the tile size used instead. + */ + if ( cc < 1 || cc > tif->tif_tilesize) + cc = tif->tif_tilesize; + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode( tif, (tidata_t) data, cc ); + + if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample)) + return ((tsize_t) 0); + if (!(*tif->tif_postencode)(tif)) + return ((tsize_t) -1); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((unsigned char *)tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, + tif->tif_rawdata, tif->tif_rawcc)) + return ((tsize_t) -1); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * There must be space for the data; we don't check + * if strips overlap! + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tsize_t +TIFFWriteRawTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteRawTile"; + + if (!WRITECHECKTILES(tif, module)) + return ((tsize_t) -1); + if (tile >= tif->tif_dir.td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu", + tif->tif_name, (unsigned long) tile, + (unsigned long) tif->tif_dir.td_nstrips); + return ((tsize_t) -1); + } + return (TIFFAppendToStrip(tif, tile, (tidata_t) data, cc) ? + cc : (tsize_t) -1); +} + +#define isUnspecified(tif, f) \ + (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0) + +int +TIFFSetupStrips(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + + if (isTiled(tif)) + td->td_stripsperimage = + isUnspecified(tif, FIELD_TILEDIMENSIONS) ? + td->td_samplesperpixel : TIFFNumberOfTiles(tif); + else + td->td_stripsperimage = + isUnspecified(tif, FIELD_ROWSPERSTRIP) ? + td->td_samplesperpixel : TIFFNumberOfStrips(tif); + td->td_nstrips = td->td_stripsperimage; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + td->td_stripsperimage /= td->td_samplesperpixel; + td->td_stripoffset = (uint32 *) + _TIFFmalloc(td->td_nstrips * sizeof (uint32)); + td->td_stripbytecount = (uint32 *) + _TIFFmalloc(td->td_nstrips * sizeof (uint32)); + if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) + return (0); + /* + * Place data at the end-of-file + * (by setting offsets to zero). + */ + _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint32)); + _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint32)); + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + return (1); +} +#undef isUnspecified + +/* + * Verify file is writable and that the directory + * information is setup properly. In doing the latter + * we also "freeze" the state of the directory so + * that important information is not changed. + */ +int +TIFFWriteCheck(TIFF* tif, int tiles, const char* module) +{ + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: File not open for writing", + tif->tif_name); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ? + "Can not write tiles to a stripped image" : + "Can not write scanlines to a tiled image"); + return (0); + } + + /* + * On the first write verify all the required information + * has been setup and initialize any data structures that + * had to wait until directory information was set. + * Note that a lot of our work is assumed to remain valid + * because we disallow any of the important parameters + * from changing after we start writing (i.e. once + * TIFF_BEENWRITING is set, TIFFSetField will only allow + * the image's length to be changed). + */ + if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Must set \"ImageWidth\" before writing data", + tif->tif_name); + return (0); + } + if (tif->tif_dir.td_samplesperpixel == 1) { + /* + * Planarconfiguration is irrelevant in case of single band + * images and need not be included. We will set it anyway, + * because this field is used in other parts of library even + * in the single band case. + */ + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) + tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG; + } else { + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Must set \"PlanarConfiguration\" before writing data", + tif->tif_name); + return (0); + } + } + if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { + tif->tif_dir.td_nstrips = 0; + TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for %s arrays", + tif->tif_name, isTiled(tif) ? "tile" : "strip"); + return (0); + } + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1; + tif->tif_scanlinesize = TIFFScanlineSize(tif); + tif->tif_flags |= TIFF_BEENWRITING; + return (1); +} + +/* + * Setup the raw data buffer used for encoding. + */ +int +TIFFWriteBufferSetup(TIFF* tif, tdata_t bp, tsize_t size) +{ + static const char module[] = "TIFFWriteBufferSetup"; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) { + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + } + tif->tif_rawdata = NULL; + } + if (size == (tsize_t) -1) { + size = (isTiled(tif) ? + tif->tif_tilesize : TIFFStripSize(tif)); + /* + * Make raw data buffer at least 8K + */ + if (size < 8*1024) + size = 8*1024; + bp = NULL; /* NB: force malloc */ + } + if (bp == NULL) { + bp = _TIFFmalloc(size); + if (bp == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for output buffer", + tif->tif_name); + return (0); + } + tif->tif_flags |= TIFF_MYBUFFER; + } else + tif->tif_flags &= ~TIFF_MYBUFFER; + tif->tif_rawdata = (tidata_t) bp; + tif->tif_rawdatasize = size; + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (1); +} + +/* + * Grow the strip data structures by delta strips. + */ +static int +TIFFGrowStrips(TIFF* tif, int delta, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 *new_stripoffset, *new_stripbytecount; + + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + new_stripoffset = (uint32*)_TIFFrealloc(td->td_stripoffset, + (td->td_nstrips + delta) * sizeof (uint32)); + new_stripbytecount = (uint32*)_TIFFrealloc(td->td_stripbytecount, + (td->td_nstrips + delta) * sizeof (uint32)); + if (new_stripoffset == NULL || new_stripbytecount == NULL) { + if (new_stripoffset) + _TIFFfree(new_stripoffset); + if (new_stripbytecount) + _TIFFfree(new_stripbytecount); + td->td_nstrips = 0; + TIFFErrorExt(tif->tif_clientdata, module, "%s: No space to expand strip arrays", + tif->tif_name); + return (0); + } + td->td_stripoffset = new_stripoffset; + td->td_stripbytecount = new_stripbytecount; + _TIFFmemset(td->td_stripoffset + td->td_nstrips, + 0, delta*sizeof (uint32)); + _TIFFmemset(td->td_stripbytecount + td->td_nstrips, + 0, delta*sizeof (uint32)); + td->td_nstrips += delta; + return (1); +} + +/* + * Append the data to the specified strip. + */ +static int +TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc) +{ + static const char module[] = "TIFFAppendToStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { + assert(td->td_nstrips > 0); + + if( td->td_stripbytecount[strip] != 0 + && td->td_stripoffset[strip] != 0 + && td->td_stripbytecount[strip] >= cc ) + { + /* + * There is already tile data on disk, and the new tile + * data we have to will fit in the same space. The only + * aspect of this that is risky is that there could be + * more data to append to this strip before we are done + * depending on how we are getting called. + */ + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %lu", + (unsigned long)tif->tif_row); + return (0); + } + } + else + { + /* + * Seek to end of file, and set that as our location to + * write this strip. + */ + td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END); + } + + tif->tif_curoff = td->td_stripoffset[strip]; + + /* + * We are starting a fresh strip/tile, so set the size to zero. + */ + td->td_stripbytecount[strip] = 0; + } + + if (!WriteOK(tif, data, cc)) { + TIFFErrorExt(tif->tif_clientdata, module, "Write error at scanline %lu", + (unsigned long) tif->tif_row); + return (0); + } + tif->tif_curoff = tif->tif_curoff+cc; + td->td_stripbytecount[strip] += cc; + return (1); +} + +/* + * Internal version of TIFFFlushData that can be + * called by ``encodestrip routines'' w/o concern + * for infinite recursion. + */ +int +TIFFFlushData1(TIFF* tif) +{ + if (tif->tif_rawcc > 0) { + if (!isFillOrder(tif, tif->tif_dir.td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((unsigned char *)tif->tif_rawdata, + tif->tif_rawcc); + if (!TIFFAppendToStrip(tif, + isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, + tif->tif_rawdata, tif->tif_rawcc)) + return (0); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + } + return (1); +} + +/* + * Set the current write offset. This should only be + * used to set the offset to a known previous location + * (very carefully), or to 0 so that the next write gets + * appended to the end of the file. + */ +void +TIFFSetWriteOffset(TIFF* tif, toff_t off) +{ + tif->tif_curoff = off; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tif_zip.c b/thirdparty/libtiff/tif_zip.c new file mode 100644 index 00000000..15091f8d --- /dev/null +++ b/thirdparty/libtiff/tif_zip.c @@ -0,0 +1,419 @@ +/* $Id: tif_zip.c,v 1.11.2.4 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef ZIP_SUPPORT +/* + * TIFF Library. + * + * ZIP (aka Deflate) Compression Support + * + * This file is simply an interface to the zlib library written by + * Jean-loup Gailly and Mark Adler. You must use version 1.0 or later + * of the library: this code assumes the 1.0 API and also depends on + * the ability to write the zlib header multiple times (one per strip) + * which was not possible with versions prior to 0.95. Note also that + * older versions of this codec avoided this bug by supressing the header + * entirely. This means that files written with the old library cannot + * be read; they should be converted to a different compression scheme + * and then reconverted. + * + * The data format used by the zlib library is described in the files + * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the + * directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was + * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz. + */ +#include "tif_predict.h" +#include "zlib.h" + +#include + +/* + * Sigh, ZLIB_VERSION is defined as a string so there's no + * way to do a proper check here. Instead we guess based + * on the presence of #defines that were added between the + * 0.95 and 1.0 distributions. + */ +#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED) +#error "Antiquated ZLIB software; you must use version 1.0 or later" +#endif + +/* + * State block for each open TIFF + * file using ZIP compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + int zipquality; /* compression level */ + int state; /* state flags */ +#define ZSTATE_INIT_DECODE 0x01 +#define ZSTATE_INIT_ENCODE 0x02 + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} ZIPState; + +#define ZState(tif) ((ZIPState*) (tif)->tif_data) +#define DecoderState(tif) ZState(tif) +#define EncoderState(tif) ZState(tif) + +static int ZIPEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int ZIPDecode(TIFF*, tidata_t, tsize_t, tsample_t); + +static int +ZIPSetupDecode(TIFF* tif) +{ + ZIPState* sp = DecoderState(tif); + static const char module[] = "ZIPSetupDecode"; + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & ZSTATE_INIT_ENCODE) { + deflateEnd(&sp->stream); + sp->state = 0; + } + + if (inflateInit(&sp->stream) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= ZSTATE_INIT_DECODE; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +ZIPPreDecode(TIFF* tif, tsample_t s) +{ + ZIPState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + + if( (sp->state & ZSTATE_INIT_DECODE) == 0 ) + tif->tif_setupdecode( tif ); + + sp->stream.next_in = tif->tif_rawdata; + sp->stream.avail_in = tif->tif_rawcc; + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +ZIPDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + ZIPState* sp = DecoderState(tif); + static const char module[] = "ZIPDecode"; + + (void) s; + assert(sp != NULL); + assert(sp->state == ZSTATE_INIT_DECODE); + + sp->stream.next_out = op; + sp->stream.avail_out = occ; + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) + break; + if (state == Z_DATA_ERROR) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Decoding error at scanline %d, %s", + tif->tif_name, tif->tif_row, sp->stream.msg); + if (inflateSync(&sp->stream) != Z_OK) + return (0); + continue; + } + if (state != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (sp->stream.avail_out > 0); + if (sp->stream.avail_out != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Not enough data at scanline %d (short %d bytes)", + tif->tif_name, tif->tif_row, sp->stream.avail_out); + return (0); + } + return (1); +} + +static int +ZIPSetupEncode(TIFF* tif) +{ + ZIPState* sp = EncoderState(tif); + static const char module[] = "ZIPSetupEncode"; + + assert(sp != NULL); + if (sp->state & ZSTATE_INIT_DECODE) { + inflateEnd(&sp->stream); + sp->state = 0; + } + + if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= ZSTATE_INIT_ENCODE; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +ZIPPreEncode(TIFF* tif, tsample_t s) +{ + ZIPState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->state != ZSTATE_INIT_ENCODE ) + tif->tif_setupencode( tif ); + + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + return (deflateReset(&sp->stream) == Z_OK); +} + +/* + * Encode a chunk of pixels. + */ +static int +ZIPEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + ZIPState *sp = EncoderState(tif); + static const char module[] = "ZIPEncode"; + + assert(sp != NULL); + assert(sp->state == ZSTATE_INIT_ENCODE); + + (void) s; + sp->stream.next_in = bp; + sp->stream.avail_in = cc; + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Encoder error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +ZIPPostEncode(TIFF* tif) +{ + ZIPState *sp = EncoderState(tif); + static const char module[] = "ZIPPostEncode"; + int state; + + sp->stream.avail_in = 0; + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if ((int)sp->stream.avail_out != (int)tif->tif_rawdatasize) + { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +ZIPCleanup(TIFF* tif) +{ + ZIPState* sp = ZState(tif); + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->state & ZSTATE_INIT_ENCODE) { + deflateEnd(&sp->stream); + sp->state = 0; + } else if( sp->state & ZSTATE_INIT_DECODE) { + inflateEnd(&sp->stream); + sp->state = 0; + } + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +ZIPVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + ZIPState* sp = ZState(tif); + static const char module[] = "ZIPVSetField"; + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + sp->zipquality = va_arg(ap, int); + if ( sp->state&ZSTATE_INIT_ENCODE ) { + if (deflateParams(&sp->stream, + sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int +ZIPVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + ZIPState* sp = ZState(tif); + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + *va_arg(ap, int*) = sp->zipquality; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFFieldInfo zipFieldInfo[] = { + { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO, + TRUE, FALSE, "" }, +}; + +int +TIFFInitZIP(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitZIP"; + ZIPState* sp; + + assert( (scheme == COMPRESSION_DEFLATE) + || (scheme == COMPRESSION_ADOBE_DEFLATE)); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFieldInfo(tif, zipFieldInfo, + TIFFArrayCount(zipFieldInfo))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging Deflate codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (ZIPState)); + if (tif->tif_data == NULL) + goto bad; + sp = ZState(tif); + sp->stream.zalloc = NULL; + sp->stream.zfree = NULL; + sp->stream.opaque = NULL; + sp->stream.data_type = Z_BINARY; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = ZIPVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = ZIPVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = ZIPSetupDecode; + tif->tif_predecode = ZIPPreDecode; + tif->tif_decoderow = ZIPDecode; + tif->tif_decodestrip = ZIPDecode; + tif->tif_decodetile = ZIPDecode; + tif->tif_setupencode = ZIPSetupEncode; + tif->tif_preencode = ZIPPreEncode; + tif->tif_postencode = ZIPPostEncode; + tif->tif_encoderow = ZIPEncode; + tif->tif_encodestrip = ZIPEncode; + tif->tif_encodetile = ZIPEncode; + tif->tif_cleanup = ZIPCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for ZIP state block"); + return (0); +} +#endif /* ZIP_SUPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/libtiff/tiff.h b/thirdparty/libtiff/tiff.h similarity index 91% rename from libs/libtiff/tiff.h rename to thirdparty/libtiff/tiff.h index 4c95eda6..0d4ab9f8 100644 --- a/libs/libtiff/tiff.h +++ b/thirdparty/libtiff/tiff.h @@ -1,4 +1,4 @@ -/* $Id: tiff.h,v 1.65 2010-03-10 18:56:49 bfriesen Exp $ */ +/* $Id: tiff.h,v 1.43.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -39,75 +39,87 @@ * Suite 200 * Seattle, WA 98104 * 206-622-5500 - * + * * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf) * - * For BigTIFF design notes see the following links + * For Big TIFF design notes see the following link * http://www.remotesensing.org/libtiff/bigtiffdesign.html - * http://www.awaresystems.be/imaging/tiff/bigtiff.html */ +#define TIFF_VERSION 42 +#define TIFF_BIGTIFF_VERSION 43 -#define TIFF_VERSION_CLASSIC 42 -#define TIFF_VERSION_BIG 43 - -#define TIFF_BIGENDIAN 0x4d4d -#define TIFF_LITTLEENDIAN 0x4949 -#define MDI_LITTLEENDIAN 0x5045 -#define MDI_BIGENDIAN 0x4550 - +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 +#define MDI_LITTLEENDIAN 0x5045 +#define MDI_BIGENDIAN 0x4550 /* * Intrinsic data types required by the file format: * - * 8-bit quantities int8/uint8 - * 16-bit quantities int16/uint16 - * 32-bit quantities int32/uint32 - * 64-bit quantities int64/uint64 - * strings unsigned char* + * 8-bit quantities int8/uint8 + * 16-bit quantities int16/uint16 + * 32-bit quantities int32/uint32 + * strings unsigned char* */ -typedef TIFF_INT8_T int8; -typedef TIFF_UINT8_T uint8; +#ifndef HAVE_INT8 +typedef signed char int8; /* NB: non-ANSI compilers may not grok */ +#endif +typedef unsigned char uint8; +#ifndef HAVE_INT16 +typedef short int16; +#endif +typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ +#if SIZEOF_INT == 4 +#ifndef HAVE_INT32 +typedef int int32; +#endif +typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ +#elif SIZEOF_LONG == 4 +#ifndef HAVE_INT32 +typedef long int32; +#endif +typedef unsigned long uint32; /* sizeof (uint32) must == 4 */ +#endif -typedef TIFF_INT16_T int16; -typedef TIFF_UINT16_T uint16; - -typedef TIFF_INT32_T int32; -typedef TIFF_UINT32_T uint32; - -typedef TIFF_INT64_T int64; -typedef TIFF_UINT64_T uint64; - -/* - * Some types as promoted in a variable argument list - * We use uint16_vap rather then directly using int, because this way - * we document the type we actually want to pass through, conceptually, - * rather then confusing the issue by merely stating the type it gets - * promoted to - */ - -typedef int uint16_vap; +/* For TIFFReassignTagToIgnore */ +enum TIFFIgnoreSense /* IGNORE tag table */ +{ + TIS_STORE, + TIS_EXTRACT, + TIS_EMPTY +}; /* * TIFF header. */ -typedef struct { - uint16 tiff_magic; /* magic number (defines byte order) */ - uint16 tiff_version; /* TIFF version number */ -} TIFFHeaderCommon; -typedef struct { - uint16 tiff_magic; /* magic number (defines byte order) */ - uint16 tiff_version; /* TIFF version number */ - uint32 tiff_diroff; /* byte offset to first directory */ -} TIFFHeaderClassic; -typedef struct { - uint16 tiff_magic; /* magic number (defines byte order) */ - uint16 tiff_version; /* TIFF version number */ - uint16 tiff_offsetsize; /* size of offsets, should be 8 */ - uint16 tiff_unused; /* unused word, should be 0 */ - uint64 tiff_diroff; /* byte offset to first directory */ -} TIFFHeaderBig; +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ +#define TIFF_MAGIC_SIZE 2 + uint16 tiff_version; /* TIFF version number */ +#define TIFF_VERSION_SIZE 2 + uint32 tiff_diroff; /* byte offset to first directory */ +#define TIFF_DIROFFSET_SIZE 4 +} TIFFHeader; +/* + * TIFF Image File Directories are comprised of a table of field + * descriptors of the form shown below. The table is sorted in + * ascending order by tag. The values associated with each entry are + * disjoint and may appear anywhere in the file (so long as they are + * placed on a word boundary). + * + * If the value is 4 bytes or less, then it is placed in the offset + * field to save space. If the value is less than 4 bytes, it is + * left-justified in the offset field. + */ +typedef struct { + uint16 tdir_tag; /* see below */ + uint16 tdir_type; /* data type; see below */ + uint32 tdir_count; /* number of items; length in spec */ + uint32 tdir_offset; /* byte offset to field data */ +} TIFFDirEntry; + /* * NB: In the comments below, * - items marked with a + are obsoleted by revision 5.0, @@ -122,24 +134,21 @@ typedef struct { * * Note: RATIONALs are the ratio of two 32-bit integer values. */ -typedef enum { - TIFF_NOTYPE = 0, /* placeholder */ - TIFF_BYTE = 1, /* 8-bit unsigned integer */ - TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ - TIFF_SHORT = 3, /* 16-bit unsigned integer */ - TIFF_LONG = 4, /* 32-bit unsigned integer */ - TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ - TIFF_SBYTE = 6, /* !8-bit signed integer */ - TIFF_UNDEFINED = 7, /* !8-bit untyped data */ - TIFF_SSHORT = 8, /* !16-bit signed integer */ - TIFF_SLONG = 9, /* !32-bit signed integer */ - TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ - TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ - TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ - TIFF_IFD = 13, /* %32-bit unsigned integer (offset) */ - TIFF_LONG8 = 16, /* BigTIFF 64-bit unsigned integer */ - TIFF_SLONG8 = 17, /* BigTIFF 64-bit signed integer */ - TIFF_IFD8 = 18 /* BigTIFF 64-bit unsigned integer (offset) */ +typedef enum { + TIFF_NOTYPE = 0, /* placeholder */ + TIFF_BYTE = 1, /* 8-bit unsigned integer */ + TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ + TIFF_SHORT = 3, /* 16-bit unsigned integer */ + TIFF_LONG = 4, /* 32-bit unsigned integer */ + TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ + TIFF_SBYTE = 6, /* !8-bit signed integer */ + TIFF_UNDEFINED = 7, /* !8-bit untyped data */ + TIFF_SSHORT = 8, /* !16-bit signed integer */ + TIFF_SLONG = 9, /* !32-bit signed integer */ + TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ + TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ + TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ + TIFF_IFD = 13 /* %32-bit unsigned integer (offset) */ } TIFFDataType; /* diff --git a/libs/libtiff/tiffconf.h b/thirdparty/libtiff/tiffconf.h similarity index 75% rename from libs/libtiff/tiffconf.h rename to thirdparty/libtiff/tiffconf.h index 7e3a7105..68dfcf01 100644 --- a/libs/libtiff/tiffconf.h +++ b/thirdparty/libtiff/tiffconf.h @@ -1,4 +1,3 @@ -/* libtiff/tiffconf.h. Generated from tiffconf.h.in by configure. */ /* Configuration defines for installed libtiff. This file maintained for backward compatibility. Do not use definitions @@ -8,36 +7,6 @@ #ifndef _TIFFCONF_ #define _TIFFCONF_ -/* Signed 16-bit type */ -#define TIFF_INT16_T signed short - -/* Signed 32-bit type */ -#define TIFF_INT32_T signed int - -/* Signed 64-bit type */ -#define TIFF_INT64_T signed long long - -/* Signed 8-bit type */ -#define TIFF_INT8_T signed char - -/* Unsigned 16-bit type */ -#define TIFF_UINT16_T unsigned short - -/* Unsigned 32-bit type */ -#define TIFF_UINT32_T unsigned int - -/* Unsigned 64-bit type */ -#define TIFF_UINT64_T unsigned long long - -/* Unsigned 8-bit type */ -#define TIFF_UINT8_T unsigned char - -/* Signed size type */ -#define TIFF_SSIZE_T signed long - -/* Pointer difference type */ -#define TIFF_PTRDIFF_T ptrdiff_t - /* Define to 1 if the system has the type `int16'. */ /* #undef HAVE_INT16 */ @@ -47,6 +16,32 @@ /* Define to 1 if the system has the type `int8'. */ /* #undef HAVE_INT8 */ +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* Signed 64-bit type formatter */ +#define TIFF_INT64_FORMAT "%I64d" + +/* Signed 64-bit type */ +#ifdef _MSC_VER +#define TIFF_INT64_T signed __int64 +#else +#define TIFF_INT64_T long long +#endif + +/* Unsigned 64-bit type formatter */ +#define TIFF_UINT64_FORMAT "%I64u" + +/* Unsigned 64-bit type */ +#ifdef _MSC_VER +#define TIFF_UINT64_T unsigned __int64 +#else +#define TIFF_UINT64_T unsigned long long +#endif + /* Compatibility stuff. */ /* Define as 0 or 1 according to the floating point format suported by the @@ -64,10 +59,7 @@ #define CCITT_SUPPORT 1 /* Support JPEG compression (requires IJG JPEG library) */ -#define JPEG_SUPPORT 1 - -/* Support JBIG compression (requires JBIG-KIT library) */ -#define JBIG_SUPPORT 1 +/* #undef JPEG_SUPPORT */ /* Support LogLuv high dynamic range encoding */ #define LOGLUV_SUPPORT 1 @@ -80,19 +72,19 @@ /* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation fails with unpatched IJG JPEG library) */ -#define OJPEG_SUPPORT 1 +/* #undef OJPEG_SUPPORT */ /* Support Macintosh PackBits algorithm */ #define PACKBITS_SUPPORT 1 /* Support Pixar log-format algorithm (requires Zlib) */ -#define PIXARLOG_SUPPORT 1 +/* #undef PIXARLOG_SUPPORT */ /* Support ThunderScan 4-bit RLE algorithm */ #define THUNDER_SUPPORT 1 /* Support Deflate compression */ -#define ZIP_SUPPORT 1 +/* #undef ZIP_SUPPORT */ /* Support strip chopping (whether or not to convert single-strip uncompressed images to mutiple strips of ~8Kb to reduce memory usage) */ @@ -110,9 +102,6 @@ lacking the tag (default enabled). */ #define CHECK_JPEG_YCBCR_SUBSAMPLING 1 -/* Support MS MDI magic number files as TIFF */ -#define MDI_SUPPORT 1 - /* * Feature support definitions. * XXX: These macros are obsoleted. Don't use them in your apps! @@ -126,3 +115,10 @@ #define IPTC_SUPPORT #endif /* _TIFFCONF_ */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libtiff/tiffio.h b/thirdparty/libtiff/tiffio.h new file mode 100644 index 00000000..36e4997a --- /dev/null +++ b/thirdparty/libtiff/tiffio.h @@ -0,0 +1,526 @@ +/* $Id: tiffio.h,v 1.56.2.4 2010-06-08 18:50:43 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets being the most important, and to ensure + * that it is unsigned, rather than signed. + */ +typedef uint32 ttag_t; /* directory tag */ +typedef uint16 tdir_t; /* directory index */ +typedef uint16 tsample_t; /* sample number */ +typedef uint32 tstrile_t; /* strip or tile number */ +typedef tstrile_t tstrip_t; /* strip number */ +typedef tstrile_t ttile_t; /* tile number */ +typedef size_t tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ +typedef uint32 toff_t; /* file offset */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_unix.c is assumed. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) +# define AVOID_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +# define VC_EXTRALEAN +# include +# ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +# else +typedef HFILE thandle_t; /* client data handle */ +# endif /* __WIN32__ */ +#else +typedef void* thandle_t; /* client data handle */ +#endif /* USE_WIN32_FILEIO */ + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * Colour conversion stuff + */ + +/* reference white */ +#define D65_X0 (95.0470F) +#define D65_Y0 (100.0F) +#define D65_Z0 (108.8827F) + +#define D50_X0 (96.4250F) +#define D50_Y0 (100.0F) +#define D50_Z0 (82.4680F) + +/* Structure for holding information about a display device. */ + +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ + +typedef struct { + float d_mat[3][3]; /* XYZ -> luminance matrix */ + float d_YCR; /* Light o/p for reference white */ + float d_YCG; + float d_YCB; + uint32 d_Vrwr; /* Pixel values for ref. white */ + uint32 d_Vrwg; + uint32 d_Vrwb; + float d_Y0R; /* Residual light for black pixel */ + float d_Y0G; + float d_Y0B; + float d_gammaR; /* Gamma values for the three guns */ + float d_gammaG; + float d_gammaB; +} TIFFDisplay; + +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32* Cr_g_tab; + int32* Cb_g_tab; + int32* Y_tab; +} TIFFYCbCrToRGB; + +typedef struct { /* CIE Lab 1976->RGB support */ + int range; /* Size of conversion table */ +#define CIELABTORGB_TABLE_RANGE 1500 + float rstep, gstep, bstep; + float X0, Y0, Z0; /* Reference white point */ + TIFFDisplay display; + float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ + float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ + float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ +} TIFFCIELabToRGB; + +/* + * RGBA-style image support. + */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32 width; /* image width */ + uint32 height; /* image height */ + uint16 bitspersample; /* image bits/sample */ + uint16 samplesperpixel; /* image samples/pixel */ + uint16 orientation; /* image orientation */ + uint16 req_orientation; /* requested orientation */ + uint16 photometric; /* image photometric interp */ + uint16* redcmap; /* colormap pallete */ + uint16* greencmap; + uint16* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); + /* put decoded strip/tile */ + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; + TIFFRGBValue* Map; /* sample mapping array */ + uint32** BWmap; /* black&white map */ + uint32** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16 scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +/* share internal LogLuv conversion routines? */ +#ifndef LOGLUV_PUBLIC +#define LOGLUV_PUBLIC 1 +#endif + +#if !defined(__GNUC__) && !defined(__attribute__) +# define __attribute__(x) /*nothing*/ +#endif + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); +typedef tsize_t (*TIFFReadWriteProc)(thandle_t, tdata_t, tsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, tdata_t*, toff_t*); +typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t, toff_t); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16); +extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); +extern int TIFFIsCODECConfigured(uint16); +extern TIFFCodec* TIFFGetConfiguredCODECs(void); + +/* + * Auxiliary functions. + */ + +extern tdata_t _TIFFmalloc(tsize_t); +extern tdata_t _TIFFrealloc(tdata_t, tsize_t); +extern void _TIFFmemset(tdata_t, int, tsize_t); +extern void _TIFFmemcpy(tdata_t, const tdata_t, tsize_t); +extern int _TIFFmemcmp(const tdata_t, const tdata_t, tsize_t); +extern void _TIFFfree(tdata_t); + +/* +** Stuff, related to tag handling and creating custom tags. +*/ +extern int TIFFGetTagListCount( TIFF * ); +extern ttag_t TIFFGetTagListEntry( TIFF *, int tag_index ); + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ + +#define FIELD_CUSTOM 65 + +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +typedef struct _TIFFTagValue { + const TIFFFieldInfo *info; + int count; + void *value; +} TIFFTagValue; + +extern void TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int); +extern const TIFFFieldInfo* TIFFFindFieldInfo(TIFF*, ttag_t, TIFFDataType); +extern const TIFFFieldInfo* TIFFFindFieldInfoByName(TIFF* , const char *, + TIFFDataType); +extern const TIFFFieldInfo* TIFFFieldWithTag(TIFF*, ttag_t); +extern const TIFFFieldInfo* TIFFFieldWithName(TIFF*, const char *); + +typedef int (*TIFFVSetMethod)(TIFF*, ttag_t, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, ttag_t, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); + +typedef struct { + TIFFVSetMethod vsetfield; /* tag set routine */ + TIFFVGetMethod vgetfield; /* tag get routine */ + TIFFPrintMethod printdir; /* directory print routine */ +} TIFFTagMethods; + +extern TIFFTagMethods *TIFFAccessTagMethods( TIFF * ); +extern void *TIFFGetClientInfo( TIFF *, const char * ); +extern void TIFFSetClientInfo( TIFF *, void *, const char * ); + +extern void TIFFCleanup(TIFF*); +extern void TIFFClose(TIFF*); +extern int TIFFFlush(TIFF*); +extern int TIFFFlushData(TIFF*); +extern int TIFFGetField(TIFF*, ttag_t, ...); +extern int TIFFVGetField(TIFF*, ttag_t, va_list); +extern int TIFFGetFieldDefaulted(TIFF*, ttag_t, ...); +extern int TIFFVGetFieldDefaulted(TIFF*, ttag_t, va_list); +extern int TIFFReadDirectory(TIFF*); +extern int TIFFReadCustomDirectory(TIFF*, toff_t, const TIFFFieldInfo[], + size_t); +extern int TIFFReadEXIFDirectory(TIFF*, toff_t); +extern tsize_t TIFFScanlineSize(TIFF*); +extern tsize_t TIFFOldScanlineSize(TIFF*); +extern tsize_t TIFFNewScanlineSize(TIFF*); +extern tsize_t TIFFRasterScanlineSize(TIFF*); +extern tsize_t TIFFStripSize(TIFF*); +extern tsize_t TIFFRawStripSize(TIFF*, tstrip_t); +extern tsize_t TIFFVStripSize(TIFF*, uint32); +extern tsize_t TIFFTileRowSize(TIFF*); +extern tsize_t TIFFTileSize(TIFF*); +extern tsize_t TIFFVTileSize(TIFF*, uint32); +extern uint32 TIFFDefaultStripSize(TIFF*, uint32); +extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int TIFFFileno(TIFF*); +extern int TIFFSetFileno(TIFF*, int); +extern thandle_t TIFFClientdata(TIFF*); +extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); +extern int TIFFGetMode(TIFF*); +extern int TIFFSetMode(TIFF*, int); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern int TIFFIsBigEndian(TIFF*); +extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); +extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); +extern TIFFSeekProc TIFFGetSeekProc(TIFF*); +extern TIFFCloseProc TIFFGetCloseProc(TIFF*); +extern TIFFSizeProc TIFFGetSizeProc(TIFF*); +extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); +extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); +extern uint32 TIFFCurrentRow(TIFF*); +extern tdir_t TIFFCurrentDirectory(TIFF*); +extern tdir_t TIFFNumberOfDirectories(TIFF*); +extern uint32 TIFFCurrentDirOffset(TIFF*); +extern tstrip_t TIFFCurrentStrip(TIFF*); +extern ttile_t TIFFCurrentTile(TIFF*); +extern int TIFFReadBufferSetup(TIFF*, tdata_t, tsize_t); +extern int TIFFWriteBufferSetup(TIFF*, tdata_t, tsize_t); +extern int TIFFSetupStrips(TIFF *); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, tdir_t); +extern int TIFFSetSubDirectory(TIFF*, uint32); +extern int TIFFUnlinkDirectory(TIFF*, tdir_t); +extern int TIFFSetField(TIFF*, ttag_t, ...); +extern int TIFFVSetField(TIFF*, ttag_t, va_list); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFCheckpointDirectory(TIFF *); +extern int TIFFRewriteDirectory(TIFF *); +extern int TIFFReassignTagToIgnore(enum TIFFIgnoreSense, int); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t = 0); +extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, + int = ORIENTATION_BOTLEFT, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t); +extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, tstrip_t, uint32 * ); +extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +# ifdef __WIN32__ +extern TIFF* TIFFOpenW(const wchar_t*, const char*); +# endif /* __WIN32__ */ +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern const char* TIFFSetFileName(TIFF*, const char *); +extern void TIFFError(const char*, const char*, ...) __attribute__((format (printf,2,3))); +extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); +extern void TIFFWarning(const char*, const char*, ...) __attribute__((format (printf,2,3))); +extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern ttile_t TIFFComputeTile(TIFF*, uint32, uint32, uint32, tsample_t); +extern int TIFFCheckTile(TIFF*, uint32, uint32, uint32, tsample_t); +extern ttile_t TIFFNumberOfTiles(TIFF*); +extern tsize_t TIFFReadTile(TIFF*, + tdata_t, uint32, uint32, uint32, tsample_t); +extern tsize_t TIFFWriteTile(TIFF*, + tdata_t, uint32, uint32, uint32, tsample_t); +extern tstrip_t TIFFComputeStrip(TIFF*, uint32, tsample_t); +extern tstrip_t TIFFNumberOfStrips(TIFF*); +extern tsize_t TIFFReadEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFReadRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFReadEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFReadRawTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteRawTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ +extern void TIFFSetWriteOffset(TIFF*, toff_t); +extern void TIFFSwabShort(uint16*); +extern void TIFFSwabLong(uint32*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16*, unsigned long); +extern void TIFFSwabArrayOfTriples(uint8*, unsigned long); +extern void TIFFSwabArrayOfLong(uint32*, unsigned long); +extern void TIFFSwabArrayOfDouble(double*, unsigned long); +extern void TIFFReverseBits(unsigned char *, unsigned long); +extern const unsigned char* TIFFGetBitRevTable(int); + +#ifdef LOGLUV_PUBLIC +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +extern double LogL16toY(int); +extern double LogL10toY(int); +extern void XYZtoRGB24(float*, uint8*); +extern int uv_decode(double*, double*, int); +extern void LogLuv24toXYZ(uint32, float*); +extern void LogLuv32toXYZ(uint32, float*); +#if defined(c_plusplus) || defined(__cplusplus) +extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); +extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); +extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); +#else +extern int LogL16fromY(double, int); +extern int LogL10fromY(double, int); +extern int uv_encode(double, double, int); +extern uint32 LogLuv24fromXYZ(float*, int); +extern uint32 LogLuv32fromXYZ(float*, int); +#endif +#endif /* LOGLUV_PUBLIC */ + +extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, TIFFDisplay *, float*); +extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, + float *, float *, float *); +extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, + uint32 *, uint32 *, uint32 *); + +extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); +extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, + uint32 *, uint32 *, uint32 *); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* _TIFFIO_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/libtiff/tiffio.hxx b/thirdparty/libtiff/tiffio.hxx old mode 100755 new mode 100644 similarity index 89% rename from libs/libtiff/tiffio.hxx rename to thirdparty/libtiff/tiffio.hxx index ed994f11..ee3fd32c --- a/libs/libtiff/tiffio.hxx +++ b/thirdparty/libtiff/tiffio.hxx @@ -1,4 +1,4 @@ -/* $Id: tiffio.hxx,v 1.3 2010-06-08 18:55:15 bfriesen Exp $ */ +/* $Id: tiffio.hxx,v 1.1.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -34,8 +34,8 @@ #include #include "tiff.h" -extern TIFF* TIFFStreamOpen(const char*, std::ostream *); -extern TIFF* TIFFStreamOpen(const char*, std::istream *); +extern TIFF* TIFFStreamOpen(const char*, std::ostream *); +extern TIFF* TIFFStreamOpen(const char*, std::istream *); #endif /* _TIFFIO_HXX_ */ diff --git a/thirdparty/libtiff/tiffiop.h b/thirdparty/libtiff/tiffiop.h new file mode 100644 index 00000000..a064039f --- /dev/null +++ b/thirdparty/libtiff/tiffiop.h @@ -0,0 +1,350 @@ +/* $Id: tiffiop.h,v 1.51.2.6 2010-06-12 02:55:16 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIOP_ +#define _TIFFIOP_ +/* + * ``Library-private'' definitions. + */ + +#include "tif_config.h" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_STRING_H +# include +#endif + +#ifdef HAVE_ASSERT_H +# include +#else +# define assert(x) +#endif + +#ifdef HAVE_SEARCH_H +# include +#else +extern void *lfind(const void *, const void *, size_t *, size_t, + int (*)(const void *, const void *)); +#endif + +/* + Libtiff itself does not require a 64-bit type, but bundled TIFF + utilities may use it. +*/ +typedef TIFF_INT64_T int64; +typedef TIFF_UINT64_T uint64; + +#include "tiffio.h" +#include "tif_dir.h" + +#ifndef STRIP_SIZE_DEFAULT +# define STRIP_SIZE_DEFAULT 8192 +#endif + +#define streq(a,b) (strcmp(a,b) == 0) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +typedef struct client_info { + struct client_info *next; + void *data; + char *name; +} TIFFClientInfoLink; + +/* + * Typedefs for ``method pointers'' used internally. + */ +typedef unsigned char tidataval_t; /* internal image data value type */ +typedef tidataval_t* tidata_t; /* reference to internal image data */ + +typedef void (*TIFFVoidMethod)(TIFF*); +typedef int (*TIFFBoolMethod)(TIFF*); +typedef int (*TIFFPreMethod)(TIFF*, tsample_t); +typedef int (*TIFFCodeMethod)(TIFF*, tidata_t, tsize_t, tsample_t); +typedef int (*TIFFSeekMethod)(TIFF*, uint32); +typedef void (*TIFFPostMethod)(TIFF*, tidata_t, tsize_t); +typedef uint32 (*TIFFStripMethod)(TIFF*, uint32); +typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*); + +struct tiff { + char* tif_name; /* name of open file */ + int tif_fd; /* open file descriptor */ + int tif_mode; /* open mode (O_*) */ + uint32 tif_flags; +#define TIFF_FILLORDER 0x00003 /* natural bit fill order for machine */ +#define TIFF_DIRTYHEADER 0x00004 /* header must be written on close */ +#define TIFF_DIRTYDIRECT 0x00008 /* current directory must be written */ +#define TIFF_BUFFERSETUP 0x00010 /* data buffers setup */ +#define TIFF_CODERSETUP 0x00020 /* encoder/decoder setup done */ +#define TIFF_BEENWRITING 0x00040 /* written 1+ scanlines to file */ +#define TIFF_SWAB 0x00080 /* byte swap file information */ +#define TIFF_NOBITREV 0x00100 /* inhibit bit reversal logic */ +#define TIFF_MYBUFFER 0x00200 /* my raw data buffer; free on close */ +#define TIFF_ISTILED 0x00400 /* file is tile, not strip- based */ +#define TIFF_MAPPED 0x00800 /* file is mapped into memory */ +#define TIFF_POSTENCODE 0x01000 /* need call to postencode routine */ +#define TIFF_INSUBIFD 0x02000 /* currently writing a subifd */ +#define TIFF_UPSAMPLED 0x04000 /* library is doing data up-sampling */ +#define TIFF_STRIPCHOP 0x08000 /* enable strip chopping support */ +#define TIFF_HEADERONLY 0x10000 /* read header only, do not process */ + /* the first directory */ +#define TIFF_NOREADRAW 0x20000 /* skip reading of raw uncompressed */ + /* image data */ +#define TIFF_INCUSTOMIFD 0x40000 /* currently writing a custom IFD */ + toff_t tif_diroff; /* file offset of current directory */ + toff_t tif_nextdiroff; /* file offset of following directory */ + toff_t* tif_dirlist; /* list of offsets to already seen */ + /* directories to prevent IFD looping */ + tsize_t tif_dirlistsize;/* number of entires in offset list */ + uint16 tif_dirnumber; /* number of already seen directories */ + TIFFDirectory tif_dir; /* internal rep of current directory */ + TIFFDirectory tif_customdir; /* custom IFDs are separated from + the main ones */ + TIFFHeader tif_header; /* file's header block */ + const int* tif_typeshift; /* data type shift counts */ + const long* tif_typemask; /* data type masks */ + uint32 tif_row; /* current scanline */ + tdir_t tif_curdir; /* current directory (index) */ + tstrip_t tif_curstrip; /* current strip for read/write */ + toff_t tif_curoff; /* current offset for read/write */ + toff_t tif_dataoff; /* current offset for writing dir */ +/* SubIFD support */ + uint16 tif_nsubifd; /* remaining subifds to write */ + toff_t tif_subifdoff; /* offset for patching SubIFD link */ +/* tiling support */ + uint32 tif_col; /* current column (offset by row too) */ + ttile_t tif_curtile; /* current tile for read/write */ + tsize_t tif_tilesize; /* # of bytes in a tile */ +/* compression scheme hooks */ + int tif_decodestatus; + TIFFBoolMethod tif_setupdecode;/* called once before predecode */ + TIFFPreMethod tif_predecode; /* pre- row/strip/tile decoding */ + TIFFBoolMethod tif_setupencode;/* called once before preencode */ + int tif_encodestatus; + TIFFPreMethod tif_preencode; /* pre- row/strip/tile encoding */ + TIFFBoolMethod tif_postencode; /* post- row/strip/tile encoding */ + TIFFCodeMethod tif_decoderow; /* scanline decoding routine */ + TIFFCodeMethod tif_encoderow; /* scanline encoding routine */ + TIFFCodeMethod tif_decodestrip;/* strip decoding routine */ + TIFFCodeMethod tif_encodestrip;/* strip encoding routine */ + TIFFCodeMethod tif_decodetile; /* tile decoding routine */ + TIFFCodeMethod tif_encodetile; /* tile encoding routine */ + TIFFVoidMethod tif_close; /* cleanup-on-close routine */ + TIFFSeekMethod tif_seek; /* position within a strip routine */ + TIFFVoidMethod tif_cleanup; /* cleanup state routine */ + TIFFStripMethod tif_defstripsize;/* calculate/constrain strip size */ + TIFFTileMethod tif_deftilesize;/* calculate/constrain tile size */ + tidata_t tif_data; /* compression scheme private data */ +/* input/output buffering */ + tsize_t tif_scanlinesize;/* # of bytes in a scanline */ + tsize_t tif_scanlineskew;/* scanline skew for reading strips */ + tidata_t tif_rawdata; /* raw data buffer */ + tsize_t tif_rawdatasize;/* # of bytes in raw data buffer */ + tidata_t tif_rawcp; /* current spot in raw buffer */ + tsize_t tif_rawcc; /* bytes unread from raw buffer */ +/* memory-mapped file support */ + tidata_t tif_base; /* base of mapped file */ + toff_t tif_size; /* size of mapped file region (bytes) + FIXME: it should be tsize_t */ + TIFFMapFileProc tif_mapproc; /* map file method */ + TIFFUnmapFileProc tif_unmapproc;/* unmap file method */ +/* input/output callback methods */ + thandle_t tif_clientdata; /* callback parameter */ + TIFFReadWriteProc tif_readproc; /* read method */ + TIFFReadWriteProc tif_writeproc;/* write method */ + TIFFSeekProc tif_seekproc; /* lseek method */ + TIFFCloseProc tif_closeproc; /* close method */ + TIFFSizeProc tif_sizeproc; /* filesize method */ +/* post-decoding support */ + TIFFPostMethod tif_postdecode; /* post decoding routine */ +/* tag support */ + TIFFFieldInfo** tif_fieldinfo; /* sorted table of registered tags */ + size_t tif_nfields; /* # entries in registered tag table */ + const TIFFFieldInfo *tif_foundfield;/* cached pointer to already found tag */ + TIFFTagMethods tif_tagmethods; /* tag get/set/print routines */ + TIFFClientInfoLink *tif_clientinfo; /* extra client information. */ +}; + +#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ + +#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0) +#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0) +#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0) +#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0) +#define TIFFReadFile(tif, buf, size) \ + ((*(tif)->tif_readproc)((tif)->tif_clientdata,buf,size)) +#define TIFFWriteFile(tif, buf, size) \ + ((*(tif)->tif_writeproc)((tif)->tif_clientdata,buf,size)) +#define TIFFSeekFile(tif, off, whence) \ + ((*(tif)->tif_seekproc)((tif)->tif_clientdata,(toff_t)(off),whence)) +#define TIFFCloseFile(tif) \ + ((*(tif)->tif_closeproc)((tif)->tif_clientdata)) +#define TIFFGetFileSize(tif) \ + ((*(tif)->tif_sizeproc)((tif)->tif_clientdata)) +#define TIFFMapFileContents(tif, paddr, psize) \ + ((*(tif)->tif_mapproc)((tif)->tif_clientdata,paddr,psize)) +#define TIFFUnmapFileContents(tif, addr, size) \ + ((*(tif)->tif_unmapproc)((tif)->tif_clientdata,addr,size)) + +/* + * Default Read/Seek/Write definitions. + */ +#ifndef ReadOK +#define ReadOK(tif, buf, size) \ + (TIFFReadFile(tif, (tdata_t) buf, (tsize_t)(size)) == (tsize_t)(size)) +#endif +#ifndef SeekOK +#define SeekOK(tif, off) \ + (TIFFSeekFile(tif, (toff_t) off, SEEK_SET) == (toff_t) off) +#endif +#ifndef WriteOK +#define WriteOK(tif, buf, size) \ + (TIFFWriteFile(tif, (tdata_t) buf, (tsize_t) size) == (tsize_t) size) +#endif + +/* NB: the uint32 casts are to silence certain ANSI-C compilers */ +#define TIFFhowmany(x, y) (((uint32)x < (0xffffffff - (uint32)(y-1))) ? \ + ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) : \ + 0U) +#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3) +#define TIFFroundup(x, y) (TIFFhowmany(x,y)*(y)) + +/* Safe multiply which returns zero if there is an integer overflow */ +#define TIFFSafeMultiply(t,v,m) ((((t)m != (t)0) && (((t)((v*m)/m)) == (t)v)) ? (t)(v*m) : (t)0) + +#define TIFFmax(A,B) ((A)>(B)?(A):(B)) +#define TIFFmin(A,B) ((A)<(B)?(A):(B)) + +#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0])) + +#if defined(__cplusplus) +extern "C" { +#endif +extern int _TIFFgetMode(const char*, const char*); +extern int _TIFFNoRowEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoStripEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoTileEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoRowDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoStripDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoTileDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern void _TIFFNoPostDecode(TIFF*, tidata_t, tsize_t); +extern int _TIFFNoPreCode (TIFF*, tsample_t); +extern int _TIFFNoSeek(TIFF*, uint32); +extern void _TIFFSwab16BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab24BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab32BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab64BitData(TIFF*, tidata_t, tsize_t); +extern int TIFFFlushData1(TIFF*); +extern int TIFFDefaultDirectory(TIFF*); +extern void _TIFFSetDefaultCompressionState(TIFF*); +extern int TIFFSetCompressionScheme(TIFF*, int); +extern int TIFFSetDefaultCompressionState(TIFF*); +extern uint32 _TIFFDefaultStripSize(TIFF*, uint32); +extern void _TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int _TIFFDataSize(TIFFDataType); + +extern void _TIFFsetByteArray(void**, void*, uint32); +extern void _TIFFsetString(char**, char*); +extern void _TIFFsetShortArray(uint16**, uint16*, uint32); +extern void _TIFFsetLongArray(uint32**, uint32*, uint32); +extern void _TIFFsetFloatArray(float**, float*, uint32); +extern void _TIFFsetDoubleArray(double**, double*, uint32); + +extern void _TIFFprintAscii(FILE*, const char*); +extern void _TIFFprintAsciiTag(FILE*, const char*, const char*); + +extern TIFFErrorHandler _TIFFwarningHandler; +extern TIFFErrorHandler _TIFFerrorHandler; +extern TIFFErrorHandlerExt _TIFFwarningHandlerExt; +extern TIFFErrorHandlerExt _TIFFerrorHandlerExt; + +extern tdata_t _TIFFCheckMalloc(TIFF*, size_t, size_t, const char*); +extern tdata_t _TIFFCheckRealloc(TIFF*, tdata_t, size_t, size_t, const char*); + +extern int TIFFInitDumpMode(TIFF*, int); +#ifdef PACKBITS_SUPPORT +extern int TIFFInitPackBits(TIFF*, int); +#endif +#ifdef CCITT_SUPPORT +extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int); +extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int); +#endif +#ifdef THUNDER_SUPPORT +extern int TIFFInitThunderScan(TIFF*, int); +#endif +#ifdef NEXT_SUPPORT +extern int TIFFInitNeXT(TIFF*, int); +#endif +#ifdef LZW_SUPPORT +extern int TIFFInitLZW(TIFF*, int); +#endif +#ifdef OJPEG_SUPPORT +extern int TIFFInitOJPEG(TIFF*, int); +#endif +#ifdef JPEG_SUPPORT +extern int TIFFInitJPEG(TIFF*, int); +#endif +#ifdef JBIG_SUPPORT +extern int TIFFInitJBIG(TIFF*, int); +#endif +#ifdef ZIP_SUPPORT +extern int TIFFInitZIP(TIFF*, int); +#endif +#ifdef PIXARLOG_SUPPORT +extern int TIFFInitPixarLog(TIFF*, int); +#endif +#ifdef LOGLUV_SUPPORT +extern int TIFFInitSGILog(TIFF*, int); +#endif +#ifdef VMS +extern const TIFFCodec _TIFFBuiltinCODECS[]; +#else +extern TIFFCodec _TIFFBuiltinCODECS[]; +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFIOP_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/libtiff/tiffvers.h b/thirdparty/libtiff/tiffvers.h similarity index 57% rename from libs/libtiff/tiffvers.h rename to thirdparty/libtiff/tiffvers.h index 88ec0591..314a22a0 100644 --- a/libs/libtiff/tiffvers.h +++ b/thirdparty/libtiff/tiffvers.h @@ -1,4 +1,4 @@ -#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.0beta6\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 3.9.4\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." /* * This define can be used in code that requires * compilation-related definitions specific to a @@ -6,4 +6,4 @@ * version checking should be done based on the * string returned by TIFFGetVersion. */ -#define TIFFLIB_VERSION 20100611 +#define TIFFLIB_VERSION 20100615 diff --git a/thirdparty/libtiff/uvcode.h b/thirdparty/libtiff/uvcode.h new file mode 100644 index 00000000..50f11d7e --- /dev/null +++ b/thirdparty/libtiff/uvcode.h @@ -0,0 +1,180 @@ +/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */ +#define UV_SQSIZ (float)0.003500 +#define UV_NDIVS 16289 +#define UV_VSTART (float)0.016940 +#define UV_NVS 163 +static struct { + float ustart; + short nus, ncum; +} uv_row[UV_NVS] = { + { (float)0.247663, 4, 0 }, + { (float)0.243779, 6, 4 }, + { (float)0.241684, 7, 10 }, + { (float)0.237874, 9, 17 }, + { (float)0.235906, 10, 26 }, + { (float)0.232153, 12, 36 }, + { (float)0.228352, 14, 48 }, + { (float)0.226259, 15, 62 }, + { (float)0.222371, 17, 77 }, + { (float)0.220410, 18, 94 }, + { (float)0.214710, 21, 112 }, + { (float)0.212714, 22, 133 }, + { (float)0.210721, 23, 155 }, + { (float)0.204976, 26, 178 }, + { (float)0.202986, 27, 204 }, + { (float)0.199245, 29, 231 }, + { (float)0.195525, 31, 260 }, + { (float)0.193560, 32, 291 }, + { (float)0.189878, 34, 323 }, + { (float)0.186216, 36, 357 }, + { (float)0.186216, 36, 393 }, + { (float)0.182592, 38, 429 }, + { (float)0.179003, 40, 467 }, + { (float)0.175466, 42, 507 }, + { (float)0.172001, 44, 549 }, + { (float)0.172001, 44, 593 }, + { (float)0.168612, 46, 637 }, + { (float)0.168612, 46, 683 }, + { (float)0.163575, 49, 729 }, + { (float)0.158642, 52, 778 }, + { (float)0.158642, 52, 830 }, + { (float)0.158642, 52, 882 }, + { (float)0.153815, 55, 934 }, + { (float)0.153815, 55, 989 }, + { (float)0.149097, 58, 1044 }, + { (float)0.149097, 58, 1102 }, + { (float)0.142746, 62, 1160 }, + { (float)0.142746, 62, 1222 }, + { (float)0.142746, 62, 1284 }, + { (float)0.138270, 65, 1346 }, + { (float)0.138270, 65, 1411 }, + { (float)0.138270, 65, 1476 }, + { (float)0.132166, 69, 1541 }, + { (float)0.132166, 69, 1610 }, + { (float)0.126204, 73, 1679 }, + { (float)0.126204, 73, 1752 }, + { (float)0.126204, 73, 1825 }, + { (float)0.120381, 77, 1898 }, + { (float)0.120381, 77, 1975 }, + { (float)0.120381, 77, 2052 }, + { (float)0.120381, 77, 2129 }, + { (float)0.112962, 82, 2206 }, + { (float)0.112962, 82, 2288 }, + { (float)0.112962, 82, 2370 }, + { (float)0.107450, 86, 2452 }, + { (float)0.107450, 86, 2538 }, + { (float)0.107450, 86, 2624 }, + { (float)0.107450, 86, 2710 }, + { (float)0.100343, 91, 2796 }, + { (float)0.100343, 91, 2887 }, + { (float)0.100343, 91, 2978 }, + { (float)0.095126, 95, 3069 }, + { (float)0.095126, 95, 3164 }, + { (float)0.095126, 95, 3259 }, + { (float)0.095126, 95, 3354 }, + { (float)0.088276, 100, 3449 }, + { (float)0.088276, 100, 3549 }, + { (float)0.088276, 100, 3649 }, + { (float)0.088276, 100, 3749 }, + { (float)0.081523, 105, 3849 }, + { (float)0.081523, 105, 3954 }, + { (float)0.081523, 105, 4059 }, + { (float)0.081523, 105, 4164 }, + { (float)0.074861, 110, 4269 }, + { (float)0.074861, 110, 4379 }, + { (float)0.074861, 110, 4489 }, + { (float)0.074861, 110, 4599 }, + { (float)0.068290, 115, 4709 }, + { (float)0.068290, 115, 4824 }, + { (float)0.068290, 115, 4939 }, + { (float)0.068290, 115, 5054 }, + { (float)0.063573, 119, 5169 }, + { (float)0.063573, 119, 5288 }, + { (float)0.063573, 119, 5407 }, + { (float)0.063573, 119, 5526 }, + { (float)0.057219, 124, 5645 }, + { (float)0.057219, 124, 5769 }, + { (float)0.057219, 124, 5893 }, + { (float)0.057219, 124, 6017 }, + { (float)0.050985, 129, 6141 }, + { (float)0.050985, 129, 6270 }, + { (float)0.050985, 129, 6399 }, + { (float)0.050985, 129, 6528 }, + { (float)0.050985, 129, 6657 }, + { (float)0.044859, 134, 6786 }, + { (float)0.044859, 134, 6920 }, + { (float)0.044859, 134, 7054 }, + { (float)0.044859, 134, 7188 }, + { (float)0.040571, 138, 7322 }, + { (float)0.040571, 138, 7460 }, + { (float)0.040571, 138, 7598 }, + { (float)0.040571, 138, 7736 }, + { (float)0.036339, 142, 7874 }, + { (float)0.036339, 142, 8016 }, + { (float)0.036339, 142, 8158 }, + { (float)0.036339, 142, 8300 }, + { (float)0.032139, 146, 8442 }, + { (float)0.032139, 146, 8588 }, + { (float)0.032139, 146, 8734 }, + { (float)0.032139, 146, 8880 }, + { (float)0.027947, 150, 9026 }, + { (float)0.027947, 150, 9176 }, + { (float)0.027947, 150, 9326 }, + { (float)0.023739, 154, 9476 }, + { (float)0.023739, 154, 9630 }, + { (float)0.023739, 154, 9784 }, + { (float)0.023739, 154, 9938 }, + { (float)0.019504, 158, 10092 }, + { (float)0.019504, 158, 10250 }, + { (float)0.019504, 158, 10408 }, + { (float)0.016976, 161, 10566 }, + { (float)0.016976, 161, 10727 }, + { (float)0.016976, 161, 10888 }, + { (float)0.016976, 161, 11049 }, + { (float)0.012639, 165, 11210 }, + { (float)0.012639, 165, 11375 }, + { (float)0.012639, 165, 11540 }, + { (float)0.009991, 168, 11705 }, + { (float)0.009991, 168, 11873 }, + { (float)0.009991, 168, 12041 }, + { (float)0.009016, 170, 12209 }, + { (float)0.009016, 170, 12379 }, + { (float)0.009016, 170, 12549 }, + { (float)0.006217, 173, 12719 }, + { (float)0.006217, 173, 12892 }, + { (float)0.005097, 175, 13065 }, + { (float)0.005097, 175, 13240 }, + { (float)0.005097, 175, 13415 }, + { (float)0.003909, 177, 13590 }, + { (float)0.003909, 177, 13767 }, + { (float)0.002340, 177, 13944 }, + { (float)0.002389, 170, 14121 }, + { (float)0.001068, 164, 14291 }, + { (float)0.001653, 157, 14455 }, + { (float)0.000717, 150, 14612 }, + { (float)0.001614, 143, 14762 }, + { (float)0.000270, 136, 14905 }, + { (float)0.000484, 129, 15041 }, + { (float)0.001103, 123, 15170 }, + { (float)0.001242, 115, 15293 }, + { (float)0.001188, 109, 15408 }, + { (float)0.001011, 103, 15517 }, + { (float)0.000709, 97, 15620 }, + { (float)0.000301, 89, 15717 }, + { (float)0.002416, 82, 15806 }, + { (float)0.003251, 76, 15888 }, + { (float)0.003246, 69, 15964 }, + { (float)0.004141, 62, 16033 }, + { (float)0.005963, 55, 16095 }, + { (float)0.008839, 47, 16150 }, + { (float)0.010490, 40, 16197 }, + { (float)0.016994, 31, 16237 }, + { (float)0.023659, 21, 16268 }, +}; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/thirdparty/libz/CMakeLists.txt b/thirdparty/libz/CMakeLists.txt new file mode 100644 index 00000000..7cd08180 --- /dev/null +++ b/thirdparty/libz/CMakeLists.txt @@ -0,0 +1,102 @@ +#based on zlib-1.2.5/CMakeLists.txt +# +cmake_minimum_required(VERSION 2.6) +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +PROJECT(zlib C) + +INCLUDE(CheckTypeSize) +INCLUDE(CheckFunctionExists) +INCLUDE(CheckIncludeFile) +INCLUDE(CheckCSourceCompiles) + +CHECK_INCLUDE_FILE(sys/types.h HAVE_SYS_TYPES_H) +CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) +CHECK_INCLUDE_FILE(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +SET(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +IF(HAVE_SYS_TYPES_H) + LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +ENDIF() +IF(HAVE_STDINT_H) + LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +ENDIF() +IF(HAVE_STDDEF_H) + LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +ENDIF() +CHECK_TYPE_SIZE(off64_t OFF64_T) +IF(HAVE_OFF64_T) + ADD_DEFINITIONS(-D_LARGEFILE64_SOURCE=1) +ENDIF() +SET(CMAKE_REQUIRED_DEFINITIONS) # clear variable +# +# Check for fseeko +# +CHECK_FUNCTION_EXISTS(fseeko HAVE_FSEEKO) +IF(NOT HAVE_FSEEKO) + ADD_DEFINITIONS(-DNO_FSEEKO) +ENDIF() +# +# Check for unistd.h +# +CHECK_INCLUDE_FILE(unistd.h Z_HAVE_UNISTD_H) + +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_SOURCE_DIR} + ${OPENJPEG_SOURCE_DIR}/thirdparty/include +) +# +SET(EXT_HDRS + ${OPENJPEG_SOURCE_DIR}/thirdparty/include/zlib.h + ${OPENJPEG_SOURCE_DIR}/thirdparty/include/zconf.h +) + +SET(HDRS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h +) +SET(SRCS + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c +) + +SET(LIBTARGET "z") +# +ADD_LIBRARY(${LIBTARGET} STATIC ${SRCS} ${EXT_HDRS} ${HDRS}) +# +IF(MSVC) + SET_TARGET_PROPERTIES(${LIBTARGET} PROPERTIES PREFIX "lib") +ENDIF(MSVC) + +SET_TARGET_PROPERTIES(${LIBTARGET} + PROPERTIES + OUTPUT_NAME "${LIBTARGET}" + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/thirdparty/lib +) +# diff --git a/thirdparty/libz/adler32.c b/thirdparty/libz/adler32.c new file mode 100644 index 00000000..65ad6a5a --- /dev/null +++ b/thirdparty/libz/adler32.c @@ -0,0 +1,169 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2007 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define local static + +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/thirdparty/libz/compress.c b/thirdparty/libz/compress.c new file mode 100644 index 00000000..ea4dfbe9 --- /dev/null +++ b/thirdparty/libz/compress.c @@ -0,0 +1,80 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/thirdparty/libz/crc32.c b/thirdparty/libz/crc32.c new file mode 100644 index 00000000..91be372d --- /dev/null +++ b/thirdparty/libz/crc32.c @@ -0,0 +1,442 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/thirdparty/libz/crc32.h b/thirdparty/libz/crc32.h new file mode 100644 index 00000000..8053b611 --- /dev/null +++ b/thirdparty/libz/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/thirdparty/libz/deflate.c b/thirdparty/libz/deflate.c new file mode 100644 index 00000000..5c4022f3 --- /dev/null +++ b/thirdparty/libz/deflate.c @@ -0,0 +1,1834 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > s->w_size) { + length = s->w_size; + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_BLOCK); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong complen, wraplen; + Bytef *str; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (strm == Z_NULL || strm->state == Z_NULL) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return conservative bound */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + (s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush)); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (int)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/thirdparty/libz/deflate.h b/thirdparty/libz/deflate.h new file mode 100644 index 00000000..cbf0d1ea --- /dev/null +++ b/thirdparty/libz/deflate.h @@ -0,0 +1,342 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2010 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/thirdparty/libz/example.c b/thirdparty/libz/example.c new file mode 100644 index 00000000..604736f1 --- /dev/null +++ b/thirdparty/libz/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2006 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/thirdparty/libz/gzclose.c b/thirdparty/libz/gzclose.c new file mode 100644 index 00000000..caeb99a3 --- /dev/null +++ b/thirdparty/libz/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/thirdparty/libz/gzguts.h b/thirdparty/libz/gzguts.h new file mode 100644 index 00000000..0f8fb79f --- /dev/null +++ b/thirdparty/libz/gzguts.h @@ -0,0 +1,132 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifdef _MSC_VER +# include +# define vsnprintf _vsnprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifdef STDC +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default i/o buffer size -- double this for output when reading */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + z_off64_t pos; /* current position in uncompressed data */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + unsigned char *next; /* next output data to deliver or write */ + /* just for reading */ + unsigned have; /* amount of output data unused at next */ + int eof; /* true if end of input file reached */ + z_off64_t start; /* where the gzip data started, for rewinding */ + z_off64_t raw; /* where the raw data started, for seeking */ + int how; /* 0: get header, 1: copy, 2: decompress */ + int direct; /* true if last read direct, false if gzip */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/thirdparty/libz/gzlib.c b/thirdparty/libz/gzlib.c new file mode 100644 index 00000000..603e60ed --- /dev/null +++ b/thirdparty/libz/gzlib.c @@ -0,0 +1,537 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const char *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + if (state->mode == GZ_READ) { /* for reading ... */ + state->have = 0; /* no output data available */ + state->eof = 0; /* not at end of file */ + state->how = LOOK; /* look for gzip header */ + state->direct = 1; /* default for empty file */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const char *path; + int fd; + const char *mode; +{ + gz_statep state; + + /* allocate gzFile structure to return */ + state = malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* save the path name for error messages */ + state->path = malloc(strlen(path) + 1); + if (state->path == NULL) { + free(state); + return NULL; + } + strcpy(state->path, path); + + /* open the file with the appropriate mode (or just use fd) */ + state->fd = fd != -1 ? fd : + open(path, +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | ( + state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))), + 0666); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) + state->mode = GZ_WRITE; /* simplify later checks */ + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; + sprintf(path, "", fd); /* for debugging */ + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if (size == 0) + return -1; + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->pos + offset >= state->raw) { + ret = LSEEK(state->fd, offset - state->have, SEEK_CUR); + if (ret == -1) + return -1; + state->have = 0; + state->eof = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->pos += offset; + return state->pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->have) || (z_off64_t)state->have > offset ? + (unsigned)offset : state->have; + state->have -= n; + state->next += n; + state->pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? + (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->msg == NULL ? "" : state->msg; +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) + state->eof = 0; + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, save as static string */ + if (err == Z_MEM_ERROR) { + state->msg = (char *)msg; + return; + } + + /* construct error message with path */ + if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { + state->err = Z_MEM_ERROR; + state->msg = (char *)"out of memory"; + return; + } + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); + return; +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/thirdparty/libz/gzread.c b/thirdparty/libz/gzread.c new file mode 100644 index 00000000..548201ab --- /dev/null +++ b/thirdparty/libz/gzread.c @@ -0,0 +1,653 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_next4 OF((gz_statep, unsigned long *)); +local int gz_head OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_make OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + + *have = 0; + do { + ret = read(state->fd, buf + *have, len - *have); + if (ret <= 0) + break; + *have += ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + gz_avail() assumes that strm->avail_in == 0. */ +local int gz_avail(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + if (state->err != Z_OK) + return -1; + if (state->eof == 0) { + if (gz_load(state, state->in, state->size, + (unsigned *)&(strm->avail_in)) == -1) + return -1; + strm->next_in = state->in; + } + return 0; +} + +/* Get next byte from input, or -1 if end or error. */ +#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \ + (strm->avail_in == 0 ? -1 : \ + (strm->avail_in--, *(strm->next_in)++))) + +/* Get a four-byte little-endian integer and return 0 on success and the value + in *ret. Otherwise -1 is returned and *ret is not modified. */ +local int gz_next4(state, ret) + gz_statep state; + unsigned long *ret; +{ + int ch; + unsigned long val; + z_streamp strm = &(state->strm); + + val = NEXT(); + val += (unsigned)NEXT() << 8; + val += (unsigned long)NEXT() << 16; + ch = NEXT(); + if (ch == -1) + return -1; + val += (unsigned long)ch << 24; + *ret = val; + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->have must be zero. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression, and the gzip header will be skipped so + that the next available input data is the raw deflate stream. If direct + copying, then leftover input data from the input buffer will be copied to + the output buffer. In that case, all further file reads will be directly to + either the output buffer or a user buffer. If decompressing, the inflate + state and the check value will be initialized. gz_head() will return 0 on + success or -1 on failure. Failures may include read errors or gzip header + errors. */ +local int gz_head(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + int flags; + unsigned len; + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = malloc(state->want); + state->out = malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get some data in the input buffer */ + if (strm->avail_in == 0) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for the gzip magic header bytes 31 and 139 */ + if (strm->next_in[0] == 31) { + strm->avail_in--; + strm->next_in++; + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in && strm->next_in[0] == 139) { + /* we have a gzip header, woo hoo! */ + strm->avail_in--; + strm->next_in++; + + /* skip rest of header */ + if (NEXT() != 8) { /* compression method */ + gz_error(state, Z_DATA_ERROR, "unknown compression method"); + return -1; + } + flags = NEXT(); + if (flags & 0xe0) { /* reserved flag bits */ + gz_error(state, Z_DATA_ERROR, "unknown header flags set"); + return -1; + } + NEXT(); /* modification time */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); /* extra flags */ + NEXT(); /* operating system */ + if (flags & 4) { /* extra field */ + len = (unsigned)NEXT(); + len += (unsigned)NEXT() << 8; + while (len--) + if (NEXT() < 0) + break; + } + if (flags & 8) /* file name */ + while (NEXT() > 0) + ; + if (flags & 16) /* comment */ + while (NEXT() > 0) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + /* an unexpected end of file is not checked for here -- it will be + noticed on the first request for uncompressed data */ + + /* set up for decompression */ + inflateReset(strm); + strm->adler = crc32(0L, Z_NULL, 0); + state->how = GZIP; + state->direct = 0; + return 0; + } + else { + /* not a gzip file -- save first byte (31) and fall to raw i/o */ + state->out[0] = 31; + state->have = 1; + } + } + + /* doing raw i/o, save start of raw data for seeking, copy any leftover + input to output -- this assumes that the output buffer is larger than + the input buffer, which also assures space for gzungetc() */ + state->raw = state->pos; + state->next = state->out; + if (strm->avail_in) { + memcpy(state->next + state->have, strm->next_in, strm->avail_in); + state->have += strm->avail_in; + strm->avail_in = 0; + } + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + If the end of the compressed data is reached, then verify the gzip trailer + check value and length (modulo 2^32). state->have and state->next are set + to point to the just decompressed data, and the crc is updated. If the + trailer is verified, state->how is reset to LOOK to look for the next gzip + stream or raw data, once state->have is depleted. Returns 0 on success, -1 + on failure. Failures may include invalid compressed data or a failed gzip + trailer verification. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret; + unsigned had; + unsigned long crc, len; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_DATA_ERROR, "unexpected end of file"); + return -1; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output and crc check value */ + state->have = had - strm->avail_out; + state->next = strm->next_out - state->have; + strm->adler = crc32(strm->adler, state->next, state->have); + + /* check gzip trailer if at end of deflate stream */ + if (ret == Z_STREAM_END) { + if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { + gz_error(state, Z_DATA_ERROR, "unexpected end of file"); + return -1; + } + if (crc != strm->adler) { + gz_error(state, Z_DATA_ERROR, "incorrect data check"); + return -1; + } + if (len != (strm->total_out & 0xffffffffL)) { + gz_error(state, Z_DATA_ERROR, "incorrect length check"); + return -1; + } + state->how = LOOK; /* ready for next stream, once have is 0 (leave + state->direct unchanged to remember how) */ + } + + /* good decompression */ + return 0; +} + +/* Make data and put in the output buffer. Assumes that state->have == 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for (and skipped if found) to determine wither to copy or decompress. + Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY + or GZIP unless the end of the input file has been reached and all data has + been processed. */ +local int gz_make(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + if (state->how == LOOK) { /* look for gzip header */ + if (gz_head(state) == -1) + return -1; + if (state->have) /* got some data from gz_head() */ + return 0; + } + if (state->how == COPY) { /* straight copy */ + if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1) + return -1; + state->next = state->out; + } + else if (state->how == GZIP) { /* decompress */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->have) { + n = GT_OFF(state->have) || (z_off64_t)state->have > len ? + (unsigned)len : state->have; + state->have -= n; + state->next += n; + state->pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_make(state) == -1) + return -1; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + unsigned got, n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + return -1; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* first just try copying data from the output buffer */ + if (state->have) { + n = state->have > len ? len : state->have; + memcpy(buf, state->next, n); + state->next += n; + state->have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && strm->avail_in == 0) + break; + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || len < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_make(state) == -1) + return -1; + continue; /* no progress yet -- go back to memcpy() above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, buf, len, &n) == -1) + return -1; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + strm->avail_out = len; + strm->next_out = buf; + if (gz_decomp(state) == -1) + return -1; + n = state->have; + state->have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->pos += n; + } while (len); + + /* return number of bytes read into user buffer (will fit in int) */ + return (int)got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->have) { + state->have--; + state->pos++; + return *(state->next)++; + } + + /* nothing there -- try gzread() */ + ret = gzread(file, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->have == 0) { + state->have = 1; + state->next = state->out + (state->size << 1) - 1; + state->next[0] = c; + state->pos--; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->have == (state->size << 1)) { + gz_error(state, Z_BUF_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->next == state->out) { + unsigned char *src = state->out + state->have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->next = dest; + } + state->have++; + state->next--; + state->next[0] = c; + state->pos--; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->have == 0) { + if (gz_make(state) == -1) + return NULL; /* error */ + if (state->have == 0) { /* end of file */ + if (buf == str) /* got bupkus */ + return NULL; + break; /* got something -- return it */ + } + } + + /* look for end-of-line in current output buffer */ + n = state->have > left ? left : state->have; + eol = memchr(state->next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->next, n); + state->have -= n; + state->next += n; + state->pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* found end-of-line or out of space -- terminate string and return it */ + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return 0; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->how == LOOK && state->have == 0) + (void)gz_head(state); + + /* return 1 if reading direct, 0 if decompressing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : Z_OK; +} diff --git a/thirdparty/libz/gzwrite.c b/thirdparty/libz/gzwrite.c new file mode 100644 index 00000000..e8defc68 --- /dev/null +++ b/thirdparty/libz/gzwrite.c @@ -0,0 +1,531 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on failure or 0 on success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input and output buffers */ + state->in = malloc(state->want); + state->out = malloc(state->want); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + 15 + 16, 8, state->strategy); + if (ret != Z_OK) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer */ + strm->avail_out = state->size; + strm->next_out = state->out; + state->next = strm->next_out; + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file, otherwise 0. + flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, + then the deflate() state is reset to start a new gzip stream. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, got; + unsigned have; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + have = (unsigned)(strm->next_out - state->next); + if (have && ((got = write(state->fd, state->next, have)) < 0 || + (unsigned)got != have)) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + } + state->next = strm->next_out; + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + deflateReset(strm); + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on error, 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + unsigned put = len; + unsigned n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + return 0; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + if (strm->avail_in == 0) + strm->next_in = state->in; + n = state->size - strm->avail_in; + if (n > len) + n = len; + memcpy(strm->next_in + strm->avail_in, buf, n); + strm->avail_in += n; + state->pos += n; + buf = (char *)buf + n; + len -= n; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + strm->avail_in = len; + strm->next_in = (voidp)buf; + state->pos += len; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } + + /* input was all buffered or compressed (put will fit in int) */ + return (int)put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (strm->avail_in < state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + strm->next_in[strm->avail_in++] = c; + state->pos++; + return c; + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = c; + if (gzwrite(file, buf, 1) != 1) + return -1; + return c; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + unsigned len; + + /* write string */ + len = (unsigned)strlen(str); + ret = gzwrite(file, str, len); + return ret == 0 && len != 0 ? -1 : ret; +} + +#ifdef STDC +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) +{ + int size, len; + gz_statep state; + z_streamp strm; + va_list va; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(state->in, format, va); + va_end(va); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = vsprintf(state->in, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(state->in, size, format, va); + va_end(va); + len = strlen(state->in); +# else + len = vsnprintf((char *)(state->in), size, format, va); + va_end(va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->pos += len; + return len; +} + +#else /* !STDC */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(state->in); +# else + len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->pos += len; + return len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* compress remaining data with requested flush */ + gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = 0; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + ret += gz_zero(state, state->skip); + } + + /* flush, free memory, and close file */ + ret += gz_comp(state, Z_FINISH); + (void)deflateEnd(&(state->strm)); + free(state->out); + free(state->in); + gz_error(state, Z_OK, NULL); + free(state->path); + ret += close(state->fd); + free(state); + return ret ? Z_ERRNO : Z_OK; +} diff --git a/thirdparty/libz/infback.c b/thirdparty/libz/infback.c new file mode 100644 index 00000000..af3a8c96 --- /dev/null +++ b/thirdparty/libz/infback.c @@ -0,0 +1,632 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/thirdparty/libz/inffast.c b/thirdparty/libz/inffast.c new file mode 100644 index 00000000..2f1d60b4 --- /dev/null +++ b/thirdparty/libz/inffast.c @@ -0,0 +1,340 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2008, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + PUP(out) = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + PUP(out) = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + PUP(out) = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + PUP(out) = PUP(from); + } while (--len); + continue; + } +#endif + } + from = window - OFF; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/thirdparty/libz/inffast.h b/thirdparty/libz/inffast.h new file mode 100644 index 00000000..e5c1aa4c --- /dev/null +++ b/thirdparty/libz/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/thirdparty/libz/inffixed.h b/thirdparty/libz/inffixed.h new file mode 100644 index 00000000..75ed4b59 --- /dev/null +++ b/thirdparty/libz/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/thirdparty/libz/inflate.c b/thirdparty/libz/inflate.c new file mode 100644 index 00000000..a8431abe --- /dev/null +++ b/thirdparty/libz/inflate.c @@ -0,0 +1,1480 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->window = Z_NULL; + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + else if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->sane = !subvert; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + return Z_OK; +#else + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + state = (struct inflate_state FAR *)strm->state; + return ((long)(state->back) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} diff --git a/thirdparty/libz/inflate.h b/thirdparty/libz/inflate.h new file mode 100644 index 00000000..95f4986d --- /dev/null +++ b/thirdparty/libz/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/thirdparty/libz/inftrees.c b/thirdparty/libz/inftrees.c new file mode 100644 index 00000000..11e9c52a --- /dev/null +++ b/thirdparty/libz/inftrees.c @@ -0,0 +1,330 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.5 Copyright 1995-2010 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + here.op = (unsigned char)(extra[work[sym]]); + here.val = base[work[sym]]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + here.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = here; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/thirdparty/libz/inftrees.h b/thirdparty/libz/inftrees.h new file mode 100644 index 00000000..baa53a0b --- /dev/null +++ b/thirdparty/libz/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/thirdparty/libz/minigzip.c b/thirdparty/libz/minigzip.c new file mode 100644 index 00000000..9825ccc3 --- /dev/null +++ b/thirdparty/libz/minigzip.c @@ -0,0 +1,440 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# ifdef UNDER_CE +# include +# endif +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif +#endif + +#if defined(UNDER_CE) +# include +# define perror(s) pwinerror(s) + +/* Map the Windows error number in ERROR to a locale-dependent error + message string and return a pointer to it. Typically, the values + for ERROR come from GetLastError. + + The string pointed to shall not be modified by the application, + but may be overwritten by a subsequent call to strwinerror + + The strwinerror function does not change the current setting + of GetLastError. */ + +static char *strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +static void pwinerror (s) + const char *s; +{ + if (s && *s) + fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); + else + fprintf(stderr, "%s\n", strwinerror(GetLastError ())); +} + +#endif /* UNDER_CE */ + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + size_t len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -c : write to standard output + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int copyout = 0; + int uncompr = 0; + gzFile file; + char *bname, outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + bname = strrchr(argv[0], '/'); + if (bname) + bname++; + else + bname = argv[0]; + argc--, argv++; + + if (!strcmp(bname, "gunzip")) + uncompr = 1; + else if (!strcmp(bname, "zcat")) + copyout = uncompr = 1; + + while (argc > 0) { + if (strcmp(*argv, "-c") == 0) + copyout = 1; + else if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + if (copyout) { + SET_BINARY_MODE(stdout); + } + do { + if (uncompr) { + if (copyout) { + file = gzopen(*argv, "rb"); + if (file == NULL) + fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); + else + gz_uncompress(file, stdout); + } else { + file_uncompress(*argv); + } + } else { + if (copyout) { + FILE * in = fopen(*argv, "rb"); + + if (in == NULL) { + perror(*argv); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + + gz_compress(in, file); + } + + } else { + file_compress(*argv, outmode); + } + } + } while (argv++, --argc); + } + return 0; +} diff --git a/thirdparty/libz/trees.c b/thirdparty/libz/trees.c new file mode 100644 index 00000000..56e9bb1c --- /dev/null +++ b/thirdparty/libz/trees.c @@ -0,0 +1,1244 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2010 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/thirdparty/libz/trees.h b/thirdparty/libz/trees.h new file mode 100644 index 00000000..d35639d8 --- /dev/null +++ b/thirdparty/libz/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/thirdparty/libz/uncompr.c b/thirdparty/libz/uncompr.c new file mode 100644 index 00000000..ad98be3a --- /dev/null +++ b/thirdparty/libz/uncompr.c @@ -0,0 +1,59 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/thirdparty/libz/zlib.h b/thirdparty/libz/zlib.h new file mode 100644 index 00000000..bfbba83e --- /dev/null +++ b/thirdparty/libz/zlib.h @@ -0,0 +1,1613 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.5, April 19th, 2010 + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.5" +#define ZLIB_VERNUM 0x1250 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is never required, but can be + used to inform inflate that a faster approach may be used for the single + inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK or Z_TREES is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been + found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the + success case, the application may save the current current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef voidp gzFile; /* opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) Also "a" + can be used instead of "w" to request that the gzip stream that will be + written be appended to the file. "+" will result in an error, since reading + and writing to the same gzip file is not supported. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file was not in gzip format, gzread copies the given number of + bytes into the buffer. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream, or failing that, reading the rest + of the input file directly without decompression. The entire input file + will be read if gzread is called until it returns less than the requested + len. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. This state can change from + false to true while reading the input file if the end of a gzip stream is + reached, but is followed by data that is not another gzip stream. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# ifdef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/thirdparty/libz/zutil.c b/thirdparty/libz/zutil.c new file mode 100644 index 00000000..898ed345 --- /dev/null +++ b/thirdparty/libz/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/thirdparty/libz/zutil.h b/thirdparty/libz/zutil.h new file mode 100644 index 00000000..258fa887 --- /dev/null +++ b/thirdparty/libz/zutil.h @@ -0,0 +1,274 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#ifdef STDC +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); +void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */

td 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