LCOV - code coverage report
Current view: top level - frmts/gtiff/libtiff - tif_pixarlog.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 975 0.0 %
Date: 2026-08-22 15:37:05 Functions: 0 31 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1996-1997 Sam Leffler
       3             :  * Copyright (c) 1996 Pixar
       4             :  *
       5             :  * Permission to use, copy, modify, distribute, and sell this software and
       6             :  * its documentation for any purpose is hereby granted without fee, provided
       7             :  * that (i) the above copyright notices and this permission notice appear in
       8             :  * all copies of the software and related documentation, and (ii) the names of
       9             :  * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or
      10             :  * publicity relating to the software without the specific, prior written
      11             :  * permission of Pixar, Sam Leffler and Silicon Graphics.
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
      14             :  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
      15             :  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
      16             :  *
      17             :  * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
      18             :  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
      19             :  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
      20             :  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
      21             :  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      22             :  * OF THIS SOFTWARE.
      23             :  */
      24             : 
      25             : #include "tiffiop.h"
      26             : #ifdef PIXARLOG_SUPPORT
      27             : 
      28             : /*
      29             :  * TIFF Library.
      30             :  * PixarLog Compression Support
      31             :  *
      32             :  * Contributed by Dan McCoy.
      33             :  *
      34             :  * PixarLog film support uses the TIFF library to store companded
      35             :  * 11 bit values into a tiff file, which are compressed using the
      36             :  * zip compressor.
      37             :  *
      38             :  * The codec can take as input and produce as output 32-bit IEEE float values
      39             :  * as well as 16-bit or 8-bit unsigned integer values.
      40             :  *
      41             :  * On writing any of the above are converted into the internal
      42             :  * 11-bit log format.   In the case of  8 and 16 bit values, the
      43             :  * input is assumed to be unsigned linear color values that represent
      44             :  * the range 0-1.  In the case of IEEE values, the 0-1 range is assumed to
      45             :  * be the normal linear color range, in addition over 1 values are
      46             :  * accepted up to a value of about 25.0 to encode "hot" highlights and such.
      47             :  * The encoding is lossless for 8-bit values, slightly lossy for the
      48             :  * other bit depths.  The actual color precision should be better
      49             :  * than the human eye can perceive with extra room to allow for
      50             :  * error introduced by further image computation.  As with any quantized
      51             :  * color format, it is possible to perform image calculations which
      52             :  * expose the quantization error. This format should certainly be less
      53             :  * susceptible to such errors than standard 8-bit encodings, but more
      54             :  * susceptible than straight 16-bit or 32-bit encodings.
      55             :  *
      56             :  * On reading the internal format is converted to the desired output format.
      57             :  * The program can request which format it desires by setting the internal
      58             :  * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values:
      59             :  *  PIXARLOGDATAFMT_FLOAT     = provide IEEE float values.
      60             :  *  PIXARLOGDATAFMT_16BIT     = provide unsigned 16-bit integer values
      61             :  *  PIXARLOGDATAFMT_8BIT      = provide unsigned 8-bit integer values
      62             :  *
      63             :  * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer
      64             :  * values with the difference that if there are exactly three or four channels
      65             :  * (rgb or rgba) it swaps the channel order (bgr or abgr).
      66             :  *
      67             :  * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly
      68             :  * packed in 16-bit values.   However no tools are supplied for interpreting
      69             :  * these values.
      70             :  *
      71             :  * "hot" (over 1.0) areas written in floating point get clamped to
      72             :  * 1.0 in the integer data types.
      73             :  *
      74             :  * When the file is closed after writing, the bit depth and sample format
      75             :  * are set always to appear as if 8-bit data has been written into it.
      76             :  * That way a naive program unaware of the particulars of the encoding
      77             :  * gets the format it is most likely able to handle.
      78             :  *
      79             :  * The codec does it's own horizontal differencing step on the coded
      80             :  * values so the libraries predictor stuff should be turned off.
      81             :  * The codec also handle byte swapping the encoded values as necessary
      82             :  * since the library does not have the information necessary
      83             :  * to know the bit depth of the raw unencoded buffer.
      84             :  *
      85             :  * NOTE: This decoder does not appear to update tif_rawcp, and tif_rawcc.
      86             :  * This can cause problems with the implementation of CHUNKY_STRIP_READ_SUPPORT
      87             :  * as noted in http://trac.osgeo.org/gdal/ticket/3894.   FrankW - Jan'11
      88             :  */
      89             : 
      90             : #include "tif_predict.h"
      91             : #include "zlib.h"
      92             : 
      93             : #include <math.h>
      94             : #include <stdio.h>
      95             : #include <stdlib.h>
      96             : 
      97             : /* Tables for converting to/from 11 bit coded values */
      98             : 
      99             : #define TSIZE 2048   /* decode table size (11-bit tokens) */
     100             : #define TSIZEP1 2049 /* Plus one for slop */
     101             : #define ONE 1250     /* token value of 1.0 exactly */
     102             : #define RATIO 1.004  /* nominal ratio for log part */
     103             : 
     104             : #define CODE_MASK 0x7ff /* 11 bits. */
     105             : 
     106             : static float Fltsize;
     107             : static float LogK1, LogK2;
     108             : 
     109             : #define REPEAT(n, op)                                                          \
     110             :     {                                                                          \
     111             :         int i;                                                                 \
     112             :         i = n;                                                                 \
     113             :         do                                                                     \
     114             :         {                                                                      \
     115             :             i--;                                                               \
     116             :             op;                                                                \
     117             :         } while (i > 0);                                                       \
     118             :     }
     119             : 
     120             : /*
     121             :  * PIXARLOGDATAFMT_* buffers are application-facing user data buffers in
     122             :  * native byte order.  Use fixed-size memcpy() calls directly so optimizing
     123             :  * compilers can expand them in these per-sample paths while callers remain
     124             :  * free to provide unaligned public buffers.  _TIFFmemcpy() is an out-of-line
     125             :  * wrapper in non-LTO builds.
     126             :  */
     127           0 : static float PixarLogLoadFloatNativeUnaligned(const uint8_t *cp)
     128             : {
     129             :     float v;
     130           0 :     memcpy(&v, cp, sizeof(v));
     131           0 :     return v;
     132             : }
     133             : 
     134           0 : static void PixarLogStoreFloatNativeUnaligned(uint8_t *cp, float v)
     135             : {
     136           0 :     memcpy(cp, &v, sizeof(v));
     137           0 : }
     138             : 
     139           0 : static uint16_t PixarLogLoad16NativeUnaligned(const uint8_t *cp)
     140             : {
     141             :     uint16_t v;
     142           0 :     memcpy(&v, cp, sizeof(v));
     143           0 :     return v;
     144             : }
     145             : 
     146           0 : static void PixarLogStore16NativeUnaligned(uint8_t *cp, uint16_t v)
     147             : {
     148           0 :     memcpy(cp, &v, sizeof(v));
     149           0 : }
     150             : 
     151           0 : static void horizontalAccumulateF(uint16_t *wp, tmsize_t n, int stride,
     152             :                                   uint8_t *op, float *ToLinearF)
     153             : {
     154             :     unsigned int cr, cg, cb, ca, mask;
     155             :     float t0, t1, t2, t3;
     156             : 
     157           0 :     if (n >= stride)
     158             :     {
     159           0 :         mask = CODE_MASK;
     160           0 :         if (stride == 3)
     161             :         {
     162           0 :             t0 = ToLinearF[cr = (wp[0] & mask)];
     163           0 :             t1 = ToLinearF[cg = (wp[1] & mask)];
     164           0 :             t2 = ToLinearF[cb = (wp[2] & mask)];
     165           0 :             PixarLogStoreFloatNativeUnaligned(op, t0);
     166           0 :             PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
     167           0 :             PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
     168           0 :             n -= 3;
     169           0 :             while (n > 0)
     170             :             {
     171           0 :                 wp += 3;
     172           0 :                 op += 3 * sizeof(float);
     173           0 :                 n -= 3;
     174           0 :                 t0 = ToLinearF[(cr += wp[0]) & mask];
     175           0 :                 t1 = ToLinearF[(cg += wp[1]) & mask];
     176           0 :                 t2 = ToLinearF[(cb += wp[2]) & mask];
     177           0 :                 PixarLogStoreFloatNativeUnaligned(op, t0);
     178           0 :                 PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
     179           0 :                 PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
     180             :             }
     181             :         }
     182           0 :         else if (stride == 4)
     183             :         {
     184           0 :             t0 = ToLinearF[cr = (wp[0] & mask)];
     185           0 :             t1 = ToLinearF[cg = (wp[1] & mask)];
     186           0 :             t2 = ToLinearF[cb = (wp[2] & mask)];
     187           0 :             t3 = ToLinearF[ca = (wp[3] & mask)];
     188           0 :             PixarLogStoreFloatNativeUnaligned(op, t0);
     189           0 :             PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
     190           0 :             PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
     191           0 :             PixarLogStoreFloatNativeUnaligned(op + 3 * sizeof(float), t3);
     192           0 :             n -= 4;
     193           0 :             while (n > 0)
     194             :             {
     195           0 :                 wp += 4;
     196           0 :                 op += 4 * sizeof(float);
     197           0 :                 n -= 4;
     198           0 :                 t0 = ToLinearF[(cr += wp[0]) & mask];
     199           0 :                 t1 = ToLinearF[(cg += wp[1]) & mask];
     200           0 :                 t2 = ToLinearF[(cb += wp[2]) & mask];
     201           0 :                 t3 = ToLinearF[(ca += wp[3]) & mask];
     202           0 :                 PixarLogStoreFloatNativeUnaligned(op, t0);
     203           0 :                 PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
     204           0 :                 PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
     205           0 :                 PixarLogStoreFloatNativeUnaligned(op + 3 * sizeof(float), t3);
     206             :             }
     207             :         }
     208             :         else
     209             :         {
     210           0 :             REPEAT(stride,
     211             :                    PixarLogStoreFloatNativeUnaligned(op, ToLinearF[*wp & mask]);
     212             :                    wp++; op += sizeof(float))
     213           0 :             n -= stride;
     214           0 :             while (n > 0)
     215             :             {
     216           0 :                 REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
     217             :                        PixarLogStoreFloatNativeUnaligned(op,
     218             :                                                          ToLinearF[*wp & mask]);
     219             :                        wp++; op += sizeof(float))
     220           0 :                 n -= stride;
     221             :             }
     222             :         }
     223             :     }
     224           0 : }
     225             : 
     226           0 : static void horizontalAccumulate12(uint16_t *wp, tmsize_t n, int stride,
     227             :                                    uint8_t *op, float *ToLinearF)
     228             : {
     229             :     unsigned int cr, cg, cb, ca, mask;
     230             :     float t0, t1, t2, t3;
     231             : 
     232             : #define SCALE12 2048.0f
     233             : #define CLAMP12(t) (((t) < 3071) ? (int16_t)(uint16_t)(t) : (int16_t)3071)
     234             : 
     235           0 :     if (n >= stride)
     236             :     {
     237           0 :         mask = CODE_MASK;
     238           0 :         if (stride == 3)
     239             :         {
     240           0 :             t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12;
     241           0 :             t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12;
     242           0 :             t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12;
     243           0 :             PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
     244           0 :             PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
     245           0 :                                            (uint16_t)CLAMP12(t1));
     246           0 :             PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
     247           0 :                                            (uint16_t)CLAMP12(t2));
     248           0 :             n -= 3;
     249           0 :             while (n > 0)
     250             :             {
     251           0 :                 wp += 3;
     252           0 :                 op += 3 * sizeof(uint16_t);
     253           0 :                 n -= 3;
     254           0 :                 t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
     255           0 :                 t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
     256           0 :                 t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
     257           0 :                 PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
     258           0 :                 PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
     259           0 :                                                (uint16_t)CLAMP12(t1));
     260           0 :                 PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
     261           0 :                                                (uint16_t)CLAMP12(t2));
     262             :             }
     263             :         }
     264           0 :         else if (stride == 4)
     265             :         {
     266           0 :             t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12;
     267           0 :             t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12;
     268           0 :             t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12;
     269           0 :             t3 = ToLinearF[ca = (wp[3] & mask)] * SCALE12;
     270           0 :             PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
     271           0 :             PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
     272           0 :                                            (uint16_t)CLAMP12(t1));
     273           0 :             PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
     274           0 :                                            (uint16_t)CLAMP12(t2));
     275           0 :             PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t),
     276           0 :                                            (uint16_t)CLAMP12(t3));
     277           0 :             n -= 4;
     278           0 :             while (n > 0)
     279             :             {
     280           0 :                 wp += 4;
     281           0 :                 op += 4 * sizeof(uint16_t);
     282           0 :                 n -= 4;
     283           0 :                 t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
     284           0 :                 t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
     285           0 :                 t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
     286           0 :                 t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12;
     287           0 :                 PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
     288           0 :                 PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
     289           0 :                                                (uint16_t)CLAMP12(t1));
     290           0 :                 PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
     291           0 :                                                (uint16_t)CLAMP12(t2));
     292           0 :                 PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t),
     293           0 :                                                (uint16_t)CLAMP12(t3));
     294             :             }
     295             :         }
     296             :         else
     297             :         {
     298           0 :             REPEAT(stride, t0 = ToLinearF[*wp & mask] * SCALE12;
     299             :                    PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
     300             :                    wp++; op += sizeof(uint16_t))
     301           0 :             n -= stride;
     302           0 :             while (n > 0)
     303             :             {
     304           0 :                 REPEAT(
     305             :                     stride, *wp = (uint16_t)(*wp + wp[-stride]);
     306             :                     t0 = ToLinearF[*wp & mask] * SCALE12;
     307             :                     PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
     308             :                     wp++; op += sizeof(uint16_t))
     309           0 :                 n -= stride;
     310             :             }
     311             :         }
     312             :     }
     313           0 : }
     314             : 
     315           0 : static void horizontalAccumulate16(uint16_t *wp, tmsize_t n, int stride,
     316             :                                    uint8_t *op, uint16_t *ToLinear16)
     317             : {
     318             :     unsigned int cr, cg, cb, ca, mask;
     319             : 
     320           0 :     if (n >= stride)
     321             :     {
     322           0 :         mask = CODE_MASK;
     323           0 :         if (stride == 3)
     324             :         {
     325           0 :             PixarLogStore16NativeUnaligned(op, ToLinear16[cr = (wp[0] & mask)]);
     326           0 :             PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
     327           0 :                                            ToLinear16[cg = (wp[1] & mask)]);
     328           0 :             PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
     329           0 :                                            ToLinear16[cb = (wp[2] & mask)]);
     330           0 :             n -= 3;
     331           0 :             while (n > 0)
     332             :             {
     333           0 :                 wp += 3;
     334           0 :                 op += 3 * sizeof(uint16_t);
     335           0 :                 n -= 3;
     336           0 :                 PixarLogStore16NativeUnaligned(
     337           0 :                     op, ToLinear16[(cr += wp[0]) & mask]);
     338           0 :                 PixarLogStore16NativeUnaligned(
     339           0 :                     op + sizeof(uint16_t), ToLinear16[(cg += wp[1]) & mask]);
     340           0 :                 PixarLogStore16NativeUnaligned(
     341             :                     op + 2 * sizeof(uint16_t),
     342           0 :                     ToLinear16[(cb += wp[2]) & mask]);
     343             :             }
     344             :         }
     345           0 :         else if (stride == 4)
     346             :         {
     347           0 :             PixarLogStore16NativeUnaligned(op, ToLinear16[cr = (wp[0] & mask)]);
     348           0 :             PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
     349           0 :                                            ToLinear16[cg = (wp[1] & mask)]);
     350           0 :             PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
     351           0 :                                            ToLinear16[cb = (wp[2] & mask)]);
     352           0 :             PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t),
     353           0 :                                            ToLinear16[ca = (wp[3] & mask)]);
     354           0 :             n -= 4;
     355           0 :             while (n > 0)
     356             :             {
     357           0 :                 wp += 4;
     358           0 :                 op += 4 * sizeof(uint16_t);
     359           0 :                 n -= 4;
     360           0 :                 PixarLogStore16NativeUnaligned(
     361           0 :                     op, ToLinear16[(cr += wp[0]) & mask]);
     362           0 :                 PixarLogStore16NativeUnaligned(
     363           0 :                     op + sizeof(uint16_t), ToLinear16[(cg += wp[1]) & mask]);
     364           0 :                 PixarLogStore16NativeUnaligned(
     365             :                     op + 2 * sizeof(uint16_t),
     366           0 :                     ToLinear16[(cb += wp[2]) & mask]);
     367           0 :                 PixarLogStore16NativeUnaligned(
     368             :                     op + 3 * sizeof(uint16_t),
     369           0 :                     ToLinear16[(ca += wp[3]) & mask]);
     370             :             }
     371             :         }
     372             :         else
     373             :         {
     374           0 :             REPEAT(stride,
     375             :                    PixarLogStore16NativeUnaligned(op, ToLinear16[*wp & mask]);
     376             :                    wp++; op += sizeof(uint16_t))
     377           0 :             n -= stride;
     378           0 :             while (n > 0)
     379             :             {
     380           0 :                 REPEAT(
     381             :                     stride, *wp = (uint16_t)(*wp + wp[-stride]);
     382             :                     PixarLogStore16NativeUnaligned(op, ToLinear16[*wp & mask]);
     383             :                     wp++; op += sizeof(uint16_t))
     384           0 :                 n -= stride;
     385             :             }
     386             :         }
     387             :     }
     388           0 : }
     389             : 
     390             : /*
     391             :  * Returns the log encoded 11-bit values with the horizontal
     392             :  * differencing undone.
     393             :  */
     394           0 : static void horizontalAccumulate11(uint16_t *wp, tmsize_t n, int stride,
     395             :                                    uint8_t *op)
     396             : {
     397             :     unsigned int cr, cg, cb, ca, mask;
     398             : 
     399           0 :     if (n >= stride)
     400             :     {
     401           0 :         mask = CODE_MASK;
     402           0 :         if (stride == 3)
     403             :         {
     404           0 :             PixarLogStore16NativeUnaligned(op, wp[0]);
     405           0 :             PixarLogStore16NativeUnaligned(op + sizeof(uint16_t), wp[1]);
     406           0 :             PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t), wp[2]);
     407           0 :             cr = wp[0];
     408           0 :             cg = wp[1];
     409           0 :             cb = wp[2];
     410           0 :             n -= 3;
     411           0 :             while (n > 0)
     412             :             {
     413           0 :                 wp += 3;
     414           0 :                 op += 3 * sizeof(uint16_t);
     415           0 :                 n -= 3;
     416           0 :                 PixarLogStore16NativeUnaligned(
     417           0 :                     op, (uint16_t)((cr += wp[0]) & mask));
     418           0 :                 PixarLogStore16NativeUnaligned(
     419           0 :                     op + sizeof(uint16_t), (uint16_t)((cg += wp[1]) & mask));
     420           0 :                 PixarLogStore16NativeUnaligned(
     421             :                     op + 2 * sizeof(uint16_t),
     422           0 :                     (uint16_t)((cb += wp[2]) & mask));
     423             :             }
     424             :         }
     425           0 :         else if (stride == 4)
     426             :         {
     427           0 :             PixarLogStore16NativeUnaligned(op, wp[0]);
     428           0 :             PixarLogStore16NativeUnaligned(op + sizeof(uint16_t), wp[1]);
     429           0 :             PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t), wp[2]);
     430           0 :             PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t), wp[3]);
     431           0 :             cr = wp[0];
     432           0 :             cg = wp[1];
     433           0 :             cb = wp[2];
     434           0 :             ca = wp[3];
     435           0 :             n -= 4;
     436           0 :             while (n > 0)
     437             :             {
     438           0 :                 wp += 4;
     439           0 :                 op += 4 * sizeof(uint16_t);
     440           0 :                 n -= 4;
     441           0 :                 PixarLogStore16NativeUnaligned(
     442           0 :                     op, (uint16_t)((cr += wp[0]) & mask));
     443           0 :                 PixarLogStore16NativeUnaligned(
     444           0 :                     op + sizeof(uint16_t), (uint16_t)((cg += wp[1]) & mask));
     445           0 :                 PixarLogStore16NativeUnaligned(
     446             :                     op + 2 * sizeof(uint16_t),
     447           0 :                     (uint16_t)((cb += wp[2]) & mask));
     448           0 :                 PixarLogStore16NativeUnaligned(
     449             :                     op + 3 * sizeof(uint16_t),
     450           0 :                     (uint16_t)((ca += wp[3]) & mask));
     451             :             }
     452             :         }
     453             :         else
     454             :         {
     455           0 :             REPEAT(stride,
     456             :                    PixarLogStore16NativeUnaligned(op, (uint16_t)(*wp & mask));
     457             :                    wp++; op += sizeof(uint16_t))
     458           0 :             n -= stride;
     459           0 :             while (n > 0)
     460             :             {
     461           0 :                 REPEAT(
     462             :                     stride, *wp = (uint16_t)(*wp + wp[-stride]);
     463             :                     PixarLogStore16NativeUnaligned(op, (uint16_t)(*wp & mask));
     464             :                     wp++; op += sizeof(uint16_t))
     465           0 :                 n -= stride;
     466             :             }
     467             :         }
     468             :     }
     469           0 : }
     470             : 
     471           0 : static void horizontalAccumulate8(uint16_t *wp, tmsize_t n, int stride,
     472             :                                   unsigned char *op, unsigned char *ToLinear8)
     473             : {
     474             :     unsigned int cr, cg, cb, ca, mask;
     475             : 
     476           0 :     if (n >= stride)
     477             :     {
     478           0 :         mask = CODE_MASK;
     479           0 :         if (stride == 3)
     480             :         {
     481           0 :             op[0] = ToLinear8[cr = (wp[0] & mask)];
     482           0 :             op[1] = ToLinear8[cg = (wp[1] & mask)];
     483           0 :             op[2] = ToLinear8[cb = (wp[2] & mask)];
     484           0 :             n -= 3;
     485           0 :             while (n > 0)
     486             :             {
     487           0 :                 n -= 3;
     488           0 :                 wp += 3;
     489           0 :                 op += 3;
     490           0 :                 op[0] = ToLinear8[(cr += wp[0]) & mask];
     491           0 :                 op[1] = ToLinear8[(cg += wp[1]) & mask];
     492           0 :                 op[2] = ToLinear8[(cb += wp[2]) & mask];
     493             :             }
     494             :         }
     495           0 :         else if (stride == 4)
     496             :         {
     497           0 :             op[0] = ToLinear8[cr = (wp[0] & mask)];
     498           0 :             op[1] = ToLinear8[cg = (wp[1] & mask)];
     499           0 :             op[2] = ToLinear8[cb = (wp[2] & mask)];
     500           0 :             op[3] = ToLinear8[ca = (wp[3] & mask)];
     501           0 :             n -= 4;
     502           0 :             while (n > 0)
     503             :             {
     504           0 :                 n -= 4;
     505           0 :                 wp += 4;
     506           0 :                 op += 4;
     507           0 :                 op[0] = ToLinear8[(cr += wp[0]) & mask];
     508           0 :                 op[1] = ToLinear8[(cg += wp[1]) & mask];
     509           0 :                 op[2] = ToLinear8[(cb += wp[2]) & mask];
     510           0 :                 op[3] = ToLinear8[(ca += wp[3]) & mask];
     511             :             }
     512             :         }
     513             :         else
     514             :         {
     515           0 :             REPEAT(stride, *op = ToLinear8[*wp & mask]; wp++; op++)
     516           0 :             n -= stride;
     517           0 :             while (n > 0)
     518             :             {
     519           0 :                 REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
     520             :                        *op = ToLinear8[*wp & mask]; wp++; op++)
     521           0 :                 n -= stride;
     522             :             }
     523             :         }
     524             :     }
     525           0 : }
     526             : 
     527           0 : static void horizontalAccumulate8abgr(uint16_t *wp, tmsize_t n, int stride,
     528             :                                       unsigned char *op,
     529             :                                       unsigned char *ToLinear8)
     530             : {
     531             :     unsigned int cr, cg, cb, ca, mask;
     532             :     unsigned char t0, t1, t2, t3;
     533             : 
     534           0 :     if (n >= stride)
     535             :     {
     536           0 :         mask = CODE_MASK;
     537           0 :         if (stride == 3)
     538             :         {
     539           0 :             op[0] = 0;
     540           0 :             t1 = ToLinear8[cb = (wp[2] & mask)];
     541           0 :             t2 = ToLinear8[cg = (wp[1] & mask)];
     542           0 :             t3 = ToLinear8[cr = (wp[0] & mask)];
     543           0 :             op[1] = t1;
     544           0 :             op[2] = t2;
     545           0 :             op[3] = t3;
     546           0 :             n -= 3;
     547           0 :             while (n > 0)
     548             :             {
     549           0 :                 n -= 3;
     550           0 :                 wp += 3;
     551           0 :                 op += 4;
     552           0 :                 op[0] = 0;
     553           0 :                 t1 = ToLinear8[(cb += wp[2]) & mask];
     554           0 :                 t2 = ToLinear8[(cg += wp[1]) & mask];
     555           0 :                 t3 = ToLinear8[(cr += wp[0]) & mask];
     556           0 :                 op[1] = t1;
     557           0 :                 op[2] = t2;
     558           0 :                 op[3] = t3;
     559             :             }
     560             :         }
     561           0 :         else if (stride == 4)
     562             :         {
     563           0 :             t0 = ToLinear8[ca = (wp[3] & mask)];
     564           0 :             t1 = ToLinear8[cb = (wp[2] & mask)];
     565           0 :             t2 = ToLinear8[cg = (wp[1] & mask)];
     566           0 :             t3 = ToLinear8[cr = (wp[0] & mask)];
     567           0 :             op[0] = t0;
     568           0 :             op[1] = t1;
     569           0 :             op[2] = t2;
     570           0 :             op[3] = t3;
     571           0 :             n -= 4;
     572           0 :             while (n > 0)
     573             :             {
     574           0 :                 n -= 4;
     575           0 :                 wp += 4;
     576           0 :                 op += 4;
     577           0 :                 t0 = ToLinear8[(ca += wp[3]) & mask];
     578           0 :                 t1 = ToLinear8[(cb += wp[2]) & mask];
     579           0 :                 t2 = ToLinear8[(cg += wp[1]) & mask];
     580           0 :                 t3 = ToLinear8[(cr += wp[0]) & mask];
     581           0 :                 op[0] = t0;
     582           0 :                 op[1] = t1;
     583           0 :                 op[2] = t2;
     584           0 :                 op[3] = t3;
     585             :             }
     586             :         }
     587             :         else
     588             :         {
     589           0 :             REPEAT(stride, *op = ToLinear8[*wp & mask]; wp++; op++)
     590           0 :             n -= stride;
     591           0 :             while (n > 0)
     592             :             {
     593           0 :                 REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
     594             :                        *op = ToLinear8[*wp & mask]; wp++; op++)
     595           0 :                 n -= stride;
     596             :             }
     597             :         }
     598             :     }
     599           0 : }
     600             : 
     601             : /*
     602             :  * State block for each open TIFF
     603             :  * file using PixarLog compression/decompression.
     604             :  */
     605             : typedef struct
     606             : {
     607             :     TIFFPredictorState predict;
     608             :     z_stream stream;
     609             :     tmsize_t tbuf_size; /* only set/used on reading for now */
     610             :     uint16_t *tbuf;
     611             :     uint16_t stride;
     612             :     int state;
     613             :     int user_datafmt;
     614             :     int quality;
     615             : #define PLSTATE_INIT 1
     616             : 
     617             :     TIFFVSetMethod vgetparent; /* super-class method */
     618             :     TIFFVSetMethod vsetparent; /* super-class method */
     619             : 
     620             :     float *ToLinearF;
     621             :     uint16_t *ToLinear16;
     622             :     unsigned char *ToLinear8;
     623             :     uint16_t *FromLT2;
     624             :     uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */
     625             :     uint16_t *From8;
     626             : 
     627             : } PixarLogState;
     628             : 
     629           0 : static int PixarLogMakeTables(TIFF *tif, PixarLogState *sp)
     630             : {
     631             : 
     632             :     /*
     633             :      *    We make several tables here to convert between various external
     634             :      *    representations (float, 16-bit, and 8-bit) and the internal
     635             :      *    11-bit companded representation.  The 11-bit representation has two
     636             :      *    distinct regions.  A linear bottom end up through .018316 in steps
     637             :      *    of about .000073, and a region of constant ratio up to about 25.
     638             :      *    These floating point numbers are stored in the main table ToLinearF.
     639             :      *    All other tables are derived from this one.  The tables (and the
     640             :      *    ratios) are continuous at the internal seam.
     641             :      */
     642             : 
     643             :     int nlin, lt2size;
     644             :     int i, j;
     645             :     double b, c, linstep, v;
     646             :     float *ToLinearF;
     647             :     uint16_t *ToLinear16;
     648             :     unsigned char *ToLinear8;
     649             :     uint16_t *FromLT2;
     650             :     uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */
     651             :     uint16_t *From8;
     652             : 
     653           0 :     c = log(RATIO);
     654           0 :     nlin = (int)(1. / c); /* nlin must be an integer */
     655           0 :     c = 1. / nlin;
     656           0 :     b = exp(-c * ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */
     657           0 :     linstep = b * c * exp(1.);
     658             : 
     659           0 :     LogK1 = (float)(1. / c); /* if (v >= 2)  token = k1*log(v*k2) */
     660           0 :     LogK2 = (float)(1. / b);
     661           0 :     lt2size = (int)(2. / linstep) + 1;
     662           0 :     FromLT2 = (uint16_t *)_TIFFmallocExt(
     663           0 :         tif, (tmsize_t)((size_t)lt2size * sizeof(uint16_t)));
     664           0 :     From14 = (uint16_t *)_TIFFmallocExt(tif, 16384 * sizeof(uint16_t));
     665           0 :     From8 = (uint16_t *)_TIFFmallocExt(tif, 256 * sizeof(uint16_t));
     666           0 :     ToLinearF = (float *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(float));
     667           0 :     ToLinear16 = (uint16_t *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(uint16_t));
     668             :     ToLinear8 =
     669           0 :         (unsigned char *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(unsigned char));
     670           0 :     if (FromLT2 == NULL || From14 == NULL || From8 == NULL ||
     671           0 :         ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL)
     672             :     {
     673           0 :         if (FromLT2)
     674           0 :             _TIFFfreeExt(tif, FromLT2);
     675           0 :         if (From14)
     676           0 :             _TIFFfreeExt(tif, From14);
     677           0 :         if (From8)
     678           0 :             _TIFFfreeExt(tif, From8);
     679           0 :         if (ToLinearF)
     680           0 :             _TIFFfreeExt(tif, ToLinearF);
     681           0 :         if (ToLinear16)
     682           0 :             _TIFFfreeExt(tif, ToLinear16);
     683           0 :         if (ToLinear8)
     684           0 :             _TIFFfreeExt(tif, ToLinear8);
     685           0 :         sp->FromLT2 = NULL;
     686           0 :         sp->From14 = NULL;
     687           0 :         sp->From8 = NULL;
     688           0 :         sp->ToLinearF = NULL;
     689           0 :         sp->ToLinear16 = NULL;
     690           0 :         sp->ToLinear8 = NULL;
     691           0 :         return 0;
     692             :     }
     693             : 
     694           0 :     j = 0;
     695             : 
     696           0 :     for (i = 0; i < nlin; i++)
     697             :     {
     698           0 :         v = i * linstep;
     699           0 :         ToLinearF[j++] = (float)v;
     700             :     }
     701             : 
     702           0 :     for (i = nlin; i < TSIZE; i++)
     703           0 :         ToLinearF[j++] = (float)(b * exp(c * i));
     704             : 
     705           0 :     ToLinearF[2048] = ToLinearF[2047];
     706             : 
     707           0 :     for (i = 0; i < TSIZEP1; i++)
     708             :     {
     709           0 :         v = (double)ToLinearF[i] * 65535.0 + 0.5;
     710           0 :         ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16_t)v;
     711           0 :         v = (double)ToLinearF[i] * 255.0 + 0.5;
     712           0 :         ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v;
     713             :     }
     714             : 
     715           0 :     j = 0;
     716           0 :     for (i = 0; i < lt2size; i++)
     717             :     {
     718           0 :         if ((i * linstep) * (i * linstep) >
     719           0 :             (double)ToLinearF[j] * (double)ToLinearF[j + 1])
     720           0 :             j++;
     721           0 :         FromLT2[i] = (uint16_t)j;
     722             :     }
     723             : 
     724             :     /*
     725             :      * Since we lose info anyway on 16-bit data, we set up a 14-bit
     726             :      * table and shift 16-bit values down two bits on input.
     727             :      * saves a little table space.
     728             :      */
     729           0 :     j = 0;
     730           0 :     for (i = 0; i < 16384; i++)
     731             :     {
     732           0 :         while ((i / 16383.) * (i / 16383.) >
     733           0 :                (double)ToLinearF[j] * (double)ToLinearF[j + 1])
     734           0 :             j++;
     735           0 :         From14[i] = (uint16_t)j;
     736             :     }
     737             : 
     738           0 :     j = 0;
     739           0 :     for (i = 0; i < 256; i++)
     740             :     {
     741           0 :         while ((i / 255.) * (i / 255.) >
     742           0 :                (double)ToLinearF[j] * (double)ToLinearF[j + 1])
     743           0 :             j++;
     744           0 :         From8[i] = (uint16_t)j;
     745             :     }
     746             : 
     747           0 :     Fltsize = (float)(lt2size / 2);
     748             : 
     749           0 :     sp->ToLinearF = ToLinearF;
     750           0 :     sp->ToLinear16 = ToLinear16;
     751           0 :     sp->ToLinear8 = ToLinear8;
     752           0 :     sp->FromLT2 = FromLT2;
     753           0 :     sp->From14 = From14;
     754           0 :     sp->From8 = From8;
     755             : 
     756           0 :     return 1;
     757             : }
     758             : 
     759             : #define PixarLogDecoderState(tif) ((PixarLogState *)(tif)->tif_data)
     760             : #define PixarLogEncoderState(tif) ((PixarLogState *)(tif)->tif_data)
     761             : 
     762             : static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
     763             : static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
     764             : 
     765             : #define PIXARLOGDATAFMT_UNKNOWN -1
     766             : 
     767           0 : static int PixarLogGuessDataFmt(TIFFDirectory *td)
     768             : {
     769           0 :     int guess = PIXARLOGDATAFMT_UNKNOWN;
     770           0 :     int format = td->td_sampleformat;
     771             : 
     772             :     /* If the user didn't tell us his datafmt,
     773             :      * take our best guess from the bitspersample.
     774             :      */
     775           0 :     switch (td->td_bitspersample)
     776             :     {
     777           0 :         case 32:
     778           0 :             if (format == SAMPLEFORMAT_IEEEFP)
     779           0 :                 guess = PIXARLOGDATAFMT_FLOAT;
     780           0 :             break;
     781           0 :         case 16:
     782           0 :             if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
     783           0 :                 guess = PIXARLOGDATAFMT_16BIT;
     784           0 :             break;
     785           0 :         case 12:
     786           0 :             if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT)
     787           0 :                 guess = PIXARLOGDATAFMT_12BITPICIO;
     788           0 :             break;
     789           0 :         case 11:
     790           0 :             if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
     791           0 :                 guess = PIXARLOGDATAFMT_11BITLOG;
     792           0 :             break;
     793           0 :         case 8:
     794           0 :             if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
     795           0 :                 guess = PIXARLOGDATAFMT_8BIT;
     796           0 :             break;
     797           0 :         default:
     798           0 :             break;
     799             :     }
     800             : 
     801           0 :     return guess;
     802             : }
     803             : 
     804           0 : static tmsize_t multiply_ms(tmsize_t m1, tmsize_t m2)
     805             : {
     806           0 :     return _TIFFMultiplySSize(NULL, m1, m2, NULL);
     807             : }
     808             : 
     809           0 : static tmsize_t add_ms(tmsize_t m1, tmsize_t m2)
     810             : {
     811           0 :     assert(m1 >= 0 && m2 >= 0);
     812             :     /* if either input is zero, assume overflow already occurred */
     813           0 :     if (m1 == 0 || m2 == 0)
     814           0 :         return 0;
     815           0 :     else if (m1 > TIFF_TMSIZE_T_MAX - m2)
     816           0 :         return 0;
     817             : 
     818           0 :     return m1 + m2;
     819             : }
     820             : 
     821           0 : static int PixarLogFixupTags(TIFF *tif)
     822             : {
     823             :     (void)tif;
     824           0 :     return (1);
     825             : }
     826             : 
     827           0 : static int PixarLogSetupDecode(TIFF *tif)
     828             : {
     829             :     static const char module[] = "PixarLogSetupDecode";
     830           0 :     TIFFDirectory *td = &tif->tif_dir;
     831           0 :     PixarLogState *sp = PixarLogDecoderState(tif);
     832             :     tmsize_t tbuf_size;
     833             :     uint32_t strip_height;
     834             : 
     835           0 :     assert(sp != NULL);
     836             : 
     837             :     /* This function can possibly be called several times by */
     838             :     /* PredictorSetupDecode() if this function succeeds but */
     839             :     /* PredictorSetup() fails */
     840           0 :     if ((sp->state & PLSTATE_INIT) != 0)
     841           0 :         return 1;
     842             : 
     843           0 :     strip_height = td->td_rowsperstrip;
     844           0 :     if (strip_height > td->td_imagelength)
     845           0 :         strip_height = td->td_imagelength;
     846             : 
     847             :     /* Make sure no byte swapping happens on the data
     848             :      * after decompression. */
     849           0 :     tif->tif_postdecode = _TIFFNoPostDecode;
     850             : 
     851             :     /* for some reason, we can't do this in TIFFInitPixarLog */
     852             : 
     853           0 :     sp->stride =
     854           0 :         (td->td_planarconfig == PLANARCONFIG_CONTIG ? td->td_samplesperpixel
     855             :                                                     : 1);
     856           0 :     tbuf_size = multiply_ms(
     857           0 :         multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), strip_height),
     858             :         sizeof(uint16_t));
     859             :     /* add one more stride in case input ends mid-stride */
     860             :     tbuf_size =
     861           0 :         add_ms(tbuf_size, (tmsize_t)(sizeof(uint16_t) * (size_t)sp->stride));
     862           0 :     if (tbuf_size == 0)
     863           0 :         return (0); /* TODO: this is an error return without error report
     864             :                        through TIFFErrorExt */
     865           0 :     sp->tbuf = (uint16_t *)_TIFFmallocExt(tif, tbuf_size);
     866           0 :     if (sp->tbuf == NULL)
     867           0 :         return (0);
     868           0 :     sp->tbuf_size = tbuf_size;
     869           0 :     if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
     870           0 :         sp->user_datafmt = PixarLogGuessDataFmt(td);
     871           0 :     if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
     872             :     {
     873           0 :         _TIFFfreeExt(tif, sp->tbuf);
     874           0 :         sp->tbuf = NULL;
     875           0 :         sp->tbuf_size = 0;
     876           0 :         TIFFErrorExtR(tif, module,
     877             :                       "PixarLog compression can't handle bits depth/data "
     878             :                       "format combination (depth: %" PRIu16 ")",
     879           0 :                       td->td_bitspersample);
     880           0 :         return (0);
     881             :     }
     882             : 
     883           0 :     if (inflateInit(&sp->stream) != Z_OK)
     884             :     {
     885           0 :         _TIFFfreeExt(tif, sp->tbuf);
     886           0 :         sp->tbuf = NULL;
     887           0 :         sp->tbuf_size = 0;
     888           0 :         TIFFErrorExtR(tif, module, "%s",
     889           0 :                       sp->stream.msg ? sp->stream.msg : "(null)");
     890           0 :         return (0);
     891             :     }
     892             :     else
     893             :     {
     894           0 :         sp->state |= PLSTATE_INIT;
     895           0 :         return (1);
     896             :     }
     897             : }
     898             : 
     899             : /*
     900             :  * Setup state for decoding a strip.
     901             :  */
     902           0 : static int PixarLogPreDecode(TIFF *tif, uint16_t s)
     903             : {
     904             :     static const char module[] = "PixarLogPreDecode";
     905           0 :     PixarLogState *sp = PixarLogDecoderState(tif);
     906             : 
     907             :     (void)s;
     908           0 :     assert(sp != NULL);
     909           0 :     sp->stream.next_in = tif->tif_rawdata;
     910             :     assert(sizeof(sp->stream.avail_in) == 4); /* if this assert gets raised,
     911             :          we need to simplify this code to reflect a ZLib that is likely updated
     912             :          to deal with 8byte memory sizes, though this code will respond
     913             :          appropriately even before we simplify it */
     914           0 :     sp->stream.avail_in = (uInt)tif->tif_rawcc;
     915           0 :     if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
     916             :     {
     917           0 :         TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
     918           0 :         return (0);
     919             :     }
     920           0 :     return (inflateReset(&sp->stream) == Z_OK);
     921             : }
     922             : 
     923           0 : static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
     924             : {
     925             :     static const char module[] = "PixarLogDecode";
     926           0 :     TIFFDirectory *td = &tif->tif_dir;
     927           0 :     PixarLogState *sp = PixarLogDecoderState(tif);
     928             :     tmsize_t i;
     929             :     tmsize_t nsamples;
     930             :     tmsize_t llen;
     931             :     uint16_t *up;
     932             : 
     933           0 :     switch (sp->user_datafmt)
     934             :     {
     935           0 :         case PIXARLOGDATAFMT_FLOAT:
     936           0 :             nsamples = (tmsize_t)((uint64_t)occ /
     937             :                                   sizeof(float)); /* XXX float == 32 bits */
     938           0 :             break;
     939           0 :         case PIXARLOGDATAFMT_16BIT:
     940             :         case PIXARLOGDATAFMT_12BITPICIO:
     941             :         case PIXARLOGDATAFMT_11BITLOG:
     942           0 :             nsamples =
     943           0 :                 (tmsize_t)((uint64_t)occ /
     944             :                            sizeof(uint16_t)); /* XXX uint16_t == 16 bits */
     945           0 :             break;
     946           0 :         case PIXARLOGDATAFMT_8BIT:
     947             :         case PIXARLOGDATAFMT_8BITABGR:
     948           0 :             nsamples = occ;
     949           0 :             break;
     950           0 :         default:
     951           0 :             TIFFErrorExtR(tif, module,
     952             :                           "%" PRIu16 " bit input not supported in PixarLog",
     953           0 :                           td->td_bitspersample);
     954           0 :             memset(op, 0, (size_t)occ);
     955           0 :             return 0;
     956             :     }
     957             : 
     958             :     /* stride (≤ td_samplesperpixel, max 65535) × imagewidth: fits tmsize_t */
     959           0 :     llen = (tmsize_t)sp->stride * td->td_imagewidth;
     960             : 
     961             :     /* Fix: ABGR with stride=3 expands 3 samples to 4 output bytes per pixel */
     962           0 :     if (sp->user_datafmt == PIXARLOGDATAFMT_8BITABGR && sp->stride == 3)
     963             :     {
     964             :         /* imagewidth × 4: fits tmsize_t (imagewidth is uint32) */
     965           0 :         tmsize_t required = (tmsize_t)td->td_imagewidth * 4;
     966             :         tmsize_t max_rows;
     967             :         tmsize_t max_nsamples;
     968             : 
     969             :         /*
     970             :          * Ensure at least one expanded output row fits.
     971             :          */
     972           0 :         if (occ < required)
     973             :         {
     974           0 :             TIFFErrorExtR(tif, module,
     975             :                           "Output buffer too small for PixarLog ABGR data");
     976           0 :             memset(op, 0, (size_t)occ);
     977           0 :             return (0);
     978             :         }
     979             : 
     980             :         /*
     981             :          * The caller-provided output buffer size must represent a whole
     982             :          * number of expanded ABGR scanlines.
     983             :          */
     984           0 :         if (occ % required)
     985             :         {
     986           0 :             TIFFErrorExtR(
     987             :                 tif, module,
     988             :                 "Fractional scanline not supported for PixarLog ABGR data");
     989           0 :             memset(op, 0, (size_t)occ);
     990           0 :             return (0);
     991             :         }
     992             : 
     993             :         /*
     994             :          * PixarLogDecode() may process multiple rows per call
     995             :          * (e.g. strip decoding). Limit nsamples so the total
     996             :          * output written by the loop below never exceeds occ.
     997             :          */
     998           0 :         max_rows = occ / required;
     999           0 :         max_nsamples = max_rows * llen;
    1000             : 
    1001           0 :         if (nsamples > max_nsamples)
    1002             :         {
    1003           0 :             TIFFErrorExtR(tif, module,
    1004             :                           "Output buffer too small for PixarLog ABGR data");
    1005           0 :             memset(op, 0, (size_t)occ);
    1006           0 :             return (0);
    1007             :         }
    1008             :     }
    1009             : 
    1010             :     (void)s;
    1011           0 :     assert(sp != NULL);
    1012             : 
    1013           0 :     sp->stream.next_in = tif->tif_rawcp;
    1014           0 :     sp->stream.avail_in = (uInt)tif->tif_rawcc;
    1015             : 
    1016           0 :     sp->stream.next_out = (unsigned char *)sp->tbuf;
    1017             :     assert(sizeof(sp->stream.avail_out) == 4); /* if this assert gets raised,
    1018             :          we need to simplify this code to reflect a ZLib that is likely updated
    1019             :          to deal with 8byte memory sizes, though this code will respond
    1020             :          appropriately even before we simplify it */
    1021           0 :     sp->stream.avail_out = (uInt)((unsigned long)nsamples * sizeof(uint16_t));
    1022           0 :     if (sp->stream.avail_out != (unsigned long)nsamples * sizeof(uint16_t))
    1023             :     {
    1024           0 :         TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
    1025           0 :         memset(op, 0, (size_t)occ);
    1026           0 :         return (0);
    1027             :     }
    1028             :     /* Check that we will not fill more than what was allocated */
    1029           0 :     if ((tmsize_t)sp->stream.avail_out > sp->tbuf_size)
    1030             :     {
    1031           0 :         TIFFErrorExtR(tif, module, "sp->stream.avail_out > sp->tbuf_size");
    1032           0 :         memset(op, 0, (size_t)occ);
    1033           0 :         return (0);
    1034             :     }
    1035             :     do
    1036             :     {
    1037           0 :         int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
    1038           0 :         if (state == Z_STREAM_END)
    1039             :         {
    1040           0 :             break; /* XXX */
    1041             :         }
    1042           0 :         if (state == Z_DATA_ERROR)
    1043             :         {
    1044           0 :             TIFFErrorExtR(tif, module,
    1045             :                           "Decoding error at scanline %" PRIu32 ", %s",
    1046             :                           tif->tif_dir.td_row,
    1047           0 :                           sp->stream.msg ? sp->stream.msg : "(null)");
    1048           0 :             memset(op, 0, (size_t)occ);
    1049           0 :             return (0);
    1050             :         }
    1051           0 :         if (state != Z_OK)
    1052             :         {
    1053           0 :             TIFFErrorExtR(tif, module, "ZLib error: %s",
    1054           0 :                           sp->stream.msg ? sp->stream.msg : "(null)");
    1055           0 :             memset(op, 0, (size_t)occ);
    1056           0 :             return (0);
    1057             :         }
    1058           0 :     } while (sp->stream.avail_out > 0);
    1059             : 
    1060             :     /* hopefully, we got all the bytes we needed */
    1061           0 :     if (sp->stream.avail_out != 0)
    1062             :     {
    1063           0 :         TIFFErrorExtR(tif, module,
    1064             :                       "Not enough data at scanline %" PRIu32
    1065             :                       " (short %u bytes)",
    1066             :                       tif->tif_dir.td_row, sp->stream.avail_out);
    1067           0 :         memset(op, 0, (size_t)occ);
    1068           0 :         return (0);
    1069             :     }
    1070             : 
    1071           0 :     tif->tif_rawcp = sp->stream.next_in;
    1072           0 :     tif->tif_rawcc = sp->stream.avail_in;
    1073             : 
    1074           0 :     up = sp->tbuf;
    1075             :     /* Swap bytes in the data if from a different endian machine. */
    1076           0 :     if (tif->tif_flags & TIFF_SWAB)
    1077           0 :         TIFFSwabArrayOfShort(up, nsamples);
    1078             : 
    1079             :     /*
    1080             :      * if llen is not an exact multiple of nsamples, the decode operation
    1081             :      * may overflow the output buffer, so truncate it enough to prevent
    1082             :      * that but still salvage as much data as possible.
    1083             :      */
    1084           0 :     if (nsamples % llen)
    1085             :     {
    1086           0 :         TIFFWarningExtR(tif, module,
    1087             :                         "stride %" TIFF_SSIZE_FORMAT
    1088             :                         " is not a multiple of sample count, "
    1089             :                         "%" TIFF_SSIZE_FORMAT ", data truncated.",
    1090             :                         llen, nsamples);
    1091           0 :         nsamples -= nsamples % llen;
    1092             :     }
    1093             : 
    1094           0 :     for (i = 0; i < nsamples; i += llen, up += llen)
    1095             :     {
    1096           0 :         switch (sp->user_datafmt)
    1097             :         {
    1098           0 :             case PIXARLOGDATAFMT_FLOAT:
    1099           0 :                 horizontalAccumulateF(up, llen, sp->stride, op, sp->ToLinearF);
    1100           0 :                 op += (unsigned long)llen * sizeof(float);
    1101           0 :                 break;
    1102           0 :             case PIXARLOGDATAFMT_16BIT:
    1103           0 :                 horizontalAccumulate16(up, llen, sp->stride, op,
    1104             :                                        sp->ToLinear16);
    1105           0 :                 op += (unsigned long)llen * sizeof(uint16_t);
    1106           0 :                 break;
    1107           0 :             case PIXARLOGDATAFMT_12BITPICIO:
    1108           0 :                 horizontalAccumulate12(up, llen, sp->stride, op, sp->ToLinearF);
    1109           0 :                 op += (unsigned long)llen * sizeof(int16_t);
    1110           0 :                 break;
    1111           0 :             case PIXARLOGDATAFMT_11BITLOG:
    1112           0 :                 horizontalAccumulate11(up, llen, sp->stride, op);
    1113           0 :                 op += (unsigned long)llen * sizeof(uint16_t);
    1114           0 :                 break;
    1115           0 :             case PIXARLOGDATAFMT_8BIT:
    1116           0 :                 horizontalAccumulate8(up, llen, sp->stride, (unsigned char *)op,
    1117             :                                       sp->ToLinear8);
    1118           0 :                 op += (unsigned long)llen * sizeof(unsigned char);
    1119           0 :                 break;
    1120           0 :             case PIXARLOGDATAFMT_8BITABGR:
    1121           0 :                 horizontalAccumulate8abgr(up, llen, sp->stride,
    1122             :                                           (unsigned char *)op, sp->ToLinear8);
    1123             : 
    1124             :                 /* For stride == 3 (RGB), horizontalAccumulate8abgr expands to 4
    1125             :                  * bytes/pixel (ABGR) */
    1126           0 :                 if (sp->stride == 3)
    1127           0 :                     op += (unsigned long)td->td_imagewidth * 4;
    1128             :                 else
    1129           0 :                     op += (unsigned long)llen * sizeof(unsigned char);
    1130           0 :                 break;
    1131           0 :             default:
    1132           0 :                 TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16,
    1133           0 :                               td->td_bitspersample);
    1134           0 :                 memset(op, 0, (size_t)occ);
    1135           0 :                 return (0);
    1136             :         }
    1137             :     }
    1138             : 
    1139           0 :     return (1);
    1140             : }
    1141             : 
    1142           0 : static int PixarLogSetupEncode(TIFF *tif)
    1143             : {
    1144             :     static const char module[] = "PixarLogSetupEncode";
    1145           0 :     TIFFDirectory *td = &tif->tif_dir;
    1146           0 :     PixarLogState *sp = PixarLogEncoderState(tif);
    1147             :     tmsize_t tbuf_size;
    1148             : 
    1149           0 :     assert(sp != NULL);
    1150             : 
    1151             :     /* for some reason, we can't do this in TIFFInitPixarLog */
    1152             : 
    1153           0 :     sp->stride =
    1154           0 :         (td->td_planarconfig == PLANARCONFIG_CONTIG ? td->td_samplesperpixel
    1155             :                                                     : 1);
    1156             :     tbuf_size =
    1157           0 :         multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
    1158           0 :                                 td->td_rowsperstrip),
    1159             :                     sizeof(uint16_t));
    1160           0 :     if (tbuf_size == 0)
    1161           0 :         return (0); /* TODO: this is an error return without error report
    1162             :                        through TIFFErrorExt */
    1163           0 :     sp->tbuf = (uint16_t *)_TIFFmallocExt(tif, tbuf_size);
    1164           0 :     if (sp->tbuf == NULL)
    1165           0 :         return (0);
    1166           0 :     if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
    1167           0 :         sp->user_datafmt = PixarLogGuessDataFmt(td);
    1168           0 :     if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
    1169             :     {
    1170           0 :         TIFFErrorExtR(tif, module,
    1171             :                       "PixarLog compression can't handle %" PRIu16
    1172             :                       " bit linear encodings",
    1173           0 :                       td->td_bitspersample);
    1174           0 :         return (0);
    1175             :     }
    1176             : 
    1177           0 :     if (deflateInit(&sp->stream, sp->quality) != Z_OK)
    1178             :     {
    1179           0 :         TIFFErrorExtR(tif, module, "%s",
    1180           0 :                       sp->stream.msg ? sp->stream.msg : "(null)");
    1181           0 :         return (0);
    1182             :     }
    1183             :     else
    1184             :     {
    1185           0 :         sp->state |= PLSTATE_INIT;
    1186           0 :         return (1);
    1187             :     }
    1188             : }
    1189             : 
    1190             : /*
    1191             :  * Reset encoding state at the start of a strip.
    1192             :  */
    1193           0 : static int PixarLogPreEncode(TIFF *tif, uint16_t s)
    1194             : {
    1195             :     static const char module[] = "PixarLogPreEncode";
    1196           0 :     PixarLogState *sp = PixarLogEncoderState(tif);
    1197             : 
    1198             :     (void)s;
    1199           0 :     assert(sp != NULL);
    1200           0 :     sp->stream.next_out = tif->tif_rawdata;
    1201             :     assert(sizeof(sp->stream.avail_out) == 4); /* if this assert gets raised,
    1202             :          we need to simplify this code to reflect a ZLib that is likely updated
    1203             :          to deal with 8byte memory sizes, though this code will respond
    1204             :          appropriately even before we simplify it */
    1205           0 :     sp->stream.avail_out = (uInt)tif->tif_rawdatasize;
    1206           0 :     if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
    1207             :     {
    1208           0 :         TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
    1209           0 :         return (0);
    1210             :     }
    1211           0 :     return (deflateReset(&sp->stream) == Z_OK);
    1212             : }
    1213             : 
    1214           0 : static void horizontalDifferenceF(const uint8_t *ip, tmsize_t n, int stride,
    1215             :                                   uint16_t *wp, uint16_t *FromLT2)
    1216             : {
    1217             :     int32_t r1, g1, b1, a1, r2, g2, b2, a2, mask;
    1218           0 :     float fltsize = Fltsize;
    1219             : 
    1220             : #define CLAMP(v)                                                               \
    1221             :     ((v < (float)0.)   ? 0                                                     \
    1222             :      : (v < (float)2.) ? FromLT2[(int)(v * fltsize)]                           \
    1223             :      : (v > (float)24.2)                                                       \
    1224             :          ? 2047                                                                \
    1225             :          : (double)LogK1 * log((double)v * (double)LogK2) + 0.5)
    1226             : 
    1227           0 :     mask = CODE_MASK;
    1228           0 :     if (n >= stride)
    1229             :     {
    1230           0 :         if (stride == 3)
    1231             :         {
    1232           0 :             r2 = wp[0] = (uint16_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
    1233           0 :             g2 = wp[1] = (uint16_t)CLAMP(
    1234             :                 PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
    1235           0 :             b2 = wp[2] = (uint16_t)CLAMP(
    1236             :                 PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
    1237           0 :             n -= 3;
    1238           0 :             while (n > 0)
    1239             :             {
    1240           0 :                 n -= 3;
    1241           0 :                 wp += 3;
    1242           0 :                 ip += 3 * sizeof(float);
    1243           0 :                 r1 = (int32_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
    1244           0 :                 wp[0] = (uint16_t)((r1 - r2) & mask);
    1245           0 :                 r2 = r1;
    1246           0 :                 g1 = (int32_t)CLAMP(
    1247             :                     PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
    1248           0 :                 wp[1] = (uint16_t)((g1 - g2) & mask);
    1249           0 :                 g2 = g1;
    1250           0 :                 b1 = (int32_t)CLAMP(
    1251             :                     PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
    1252           0 :                 wp[2] = (uint16_t)((b1 - b2) & mask);
    1253           0 :                 b2 = b1;
    1254             :             }
    1255             :         }
    1256           0 :         else if (stride == 4)
    1257             :         {
    1258           0 :             r2 = wp[0] = (uint16_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
    1259           0 :             g2 = wp[1] = (uint16_t)CLAMP(
    1260             :                 PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
    1261           0 :             b2 = wp[2] = (uint16_t)CLAMP(
    1262             :                 PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
    1263           0 :             a2 = wp[3] = (uint16_t)CLAMP(
    1264             :                 PixarLogLoadFloatNativeUnaligned(ip + 3 * sizeof(float)));
    1265           0 :             n -= 4;
    1266           0 :             while (n > 0)
    1267             :             {
    1268           0 :                 n -= 4;
    1269           0 :                 wp += 4;
    1270           0 :                 ip += 4 * sizeof(float);
    1271           0 :                 r1 = (int32_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
    1272           0 :                 wp[0] = (uint16_t)((r1 - r2) & mask);
    1273           0 :                 r2 = r1;
    1274           0 :                 g1 = (int32_t)CLAMP(
    1275             :                     PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
    1276           0 :                 wp[1] = (uint16_t)((g1 - g2) & mask);
    1277           0 :                 g2 = g1;
    1278           0 :                 b1 = (int32_t)CLAMP(
    1279             :                     PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
    1280           0 :                 wp[2] = (uint16_t)((b1 - b2) & mask);
    1281           0 :                 b2 = b1;
    1282           0 :                 a1 = (int32_t)CLAMP(
    1283             :                     PixarLogLoadFloatNativeUnaligned(ip + 3 * sizeof(float)));
    1284           0 :                 wp[3] = (uint16_t)((a1 - a2) & mask);
    1285           0 :                 a2 = a1;
    1286             :             }
    1287             :         }
    1288             :         else
    1289             :         {
    1290           0 :             REPEAT(stride, wp[0] = (uint16_t)CLAMP(
    1291             :                                PixarLogLoadFloatNativeUnaligned(ip));
    1292             :                    wp++; ip += sizeof(float))
    1293           0 :             n -= stride;
    1294           0 :             while (n > 0)
    1295             :             {
    1296           0 :                 REPEAT(
    1297             :                     stride,
    1298             :                     wp[0] =
    1299             :                         (uint16_t)(((int32_t)CLAMP(
    1300             :                                         PixarLogLoadFloatNativeUnaligned(ip)) -
    1301             :                                     (int32_t)CLAMP(
    1302             :                                         PixarLogLoadFloatNativeUnaligned(
    1303             :                                             ip -
    1304             :                                             (tmsize_t)stride *
    1305             :                                                 (tmsize_t)sizeof(float)))) &
    1306             :                                    mask);
    1307             :                     wp++; ip += sizeof(float))
    1308           0 :                 n -= stride;
    1309             :             }
    1310             :         }
    1311             :     }
    1312           0 : }
    1313             : 
    1314           0 : static void horizontalDifference16(const uint8_t *ip, tmsize_t n, int stride,
    1315             :                                    unsigned short *wp, uint16_t *From14)
    1316             : {
    1317             :     int r1, g1, b1, a1, r2, g2, b2, a2, mask;
    1318             : 
    1319             : /* assumption is unsigned pixel values */
    1320             : #undef CLAMP
    1321             : #define CLAMP(v) From14[(v) >> 2]
    1322             : 
    1323           0 :     mask = CODE_MASK;
    1324           0 :     if (n >= stride)
    1325             :     {
    1326           0 :         if (stride == 3)
    1327             :         {
    1328           0 :             r2 = wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
    1329           0 :             g2 = wp[1] =
    1330           0 :                 CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
    1331           0 :             b2 = wp[2] =
    1332           0 :                 CLAMP(PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
    1333           0 :             n -= 3;
    1334           0 :             while (n > 0)
    1335             :             {
    1336           0 :                 n -= 3;
    1337           0 :                 wp += 3;
    1338           0 :                 ip += 3 * sizeof(uint16_t);
    1339           0 :                 r1 = CLAMP(PixarLogLoad16NativeUnaligned(ip));
    1340           0 :                 wp[0] = (uint16_t)((r1 - r2) & mask);
    1341           0 :                 r2 = r1;
    1342           0 :                 g1 =
    1343           0 :                     CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
    1344           0 :                 wp[1] = (uint16_t)((g1 - g2) & mask);
    1345           0 :                 g2 = g1;
    1346           0 :                 b1 = CLAMP(
    1347             :                     PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
    1348           0 :                 wp[2] = (uint16_t)((b1 - b2) & mask);
    1349           0 :                 b2 = b1;
    1350             :             }
    1351             :         }
    1352           0 :         else if (stride == 4)
    1353             :         {
    1354           0 :             r2 = wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
    1355           0 :             g2 = wp[1] =
    1356           0 :                 CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
    1357           0 :             b2 = wp[2] =
    1358           0 :                 CLAMP(PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
    1359           0 :             a2 = wp[3] =
    1360           0 :                 CLAMP(PixarLogLoad16NativeUnaligned(ip + 3 * sizeof(uint16_t)));
    1361           0 :             n -= 4;
    1362           0 :             while (n > 0)
    1363             :             {
    1364           0 :                 n -= 4;
    1365           0 :                 wp += 4;
    1366           0 :                 ip += 4 * sizeof(uint16_t);
    1367           0 :                 r1 = CLAMP(PixarLogLoad16NativeUnaligned(ip));
    1368           0 :                 wp[0] = (uint16_t)((r1 - r2) & mask);
    1369           0 :                 r2 = r1;
    1370           0 :                 g1 =
    1371           0 :                     CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
    1372           0 :                 wp[1] = (uint16_t)((g1 - g2) & mask);
    1373           0 :                 g2 = g1;
    1374           0 :                 b1 = CLAMP(
    1375             :                     PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
    1376           0 :                 wp[2] = (uint16_t)((b1 - b2) & mask);
    1377           0 :                 b2 = b1;
    1378           0 :                 a1 = CLAMP(
    1379             :                     PixarLogLoad16NativeUnaligned(ip + 3 * sizeof(uint16_t)));
    1380           0 :                 wp[3] = (uint16_t)((a1 - a2) & mask);
    1381           0 :                 a2 = a1;
    1382             :             }
    1383             :         }
    1384             :         else
    1385             :         {
    1386           0 :             REPEAT(stride, wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
    1387             :                    wp++; ip += sizeof(uint16_t))
    1388           0 :             n -= stride;
    1389           0 :             while (n > 0)
    1390             :             {
    1391           0 :                 REPEAT(
    1392             :                     stride,
    1393             :                     wp[0] =
    1394             :                         (uint16_t)((CLAMP(PixarLogLoad16NativeUnaligned(ip)) -
    1395             :                                     CLAMP(PixarLogLoad16NativeUnaligned(
    1396             :                                         ip - (tmsize_t)stride *
    1397             :                                                  (tmsize_t)sizeof(uint16_t)))) &
    1398             :                                    mask);
    1399             :                     wp++; ip += sizeof(uint16_t))
    1400           0 :                 n -= stride;
    1401             :             }
    1402             :         }
    1403             :     }
    1404           0 : }
    1405             : 
    1406           0 : static void horizontalDifference8(unsigned char *ip, tmsize_t n, int stride,
    1407             :                                   unsigned short *wp, uint16_t *From8)
    1408             : {
    1409             :     int r1, g1, b1, a1, r2, g2, b2, a2, mask;
    1410             : 
    1411             : #undef CLAMP
    1412             : #define CLAMP(v) (From8[(v)])
    1413             : 
    1414           0 :     mask = CODE_MASK;
    1415           0 :     if (n >= stride)
    1416             :     {
    1417           0 :         if (stride == 3)
    1418             :         {
    1419           0 :             r2 = wp[0] = CLAMP(ip[0]);
    1420           0 :             g2 = wp[1] = CLAMP(ip[1]);
    1421           0 :             b2 = wp[2] = CLAMP(ip[2]);
    1422           0 :             n -= 3;
    1423           0 :             while (n > 0)
    1424             :             {
    1425           0 :                 n -= 3;
    1426           0 :                 r1 = CLAMP(ip[3]);
    1427           0 :                 wp[3] = (uint16_t)((r1 - r2) & mask);
    1428           0 :                 r2 = r1;
    1429           0 :                 g1 = CLAMP(ip[4]);
    1430           0 :                 wp[4] = (uint16_t)((g1 - g2) & mask);
    1431           0 :                 g2 = g1;
    1432           0 :                 b1 = CLAMP(ip[5]);
    1433           0 :                 wp[5] = (uint16_t)((b1 - b2) & mask);
    1434           0 :                 b2 = b1;
    1435           0 :                 wp += 3;
    1436           0 :                 ip += 3;
    1437             :             }
    1438             :         }
    1439           0 :         else if (stride == 4)
    1440             :         {
    1441           0 :             r2 = wp[0] = CLAMP(ip[0]);
    1442           0 :             g2 = wp[1] = CLAMP(ip[1]);
    1443           0 :             b2 = wp[2] = CLAMP(ip[2]);
    1444           0 :             a2 = wp[3] = CLAMP(ip[3]);
    1445           0 :             n -= 4;
    1446           0 :             while (n > 0)
    1447             :             {
    1448           0 :                 n -= 4;
    1449           0 :                 r1 = CLAMP(ip[4]);
    1450           0 :                 wp[4] = (uint16_t)((r1 - r2) & mask);
    1451           0 :                 r2 = r1;
    1452           0 :                 g1 = CLAMP(ip[5]);
    1453           0 :                 wp[5] = (uint16_t)((g1 - g2) & mask);
    1454           0 :                 g2 = g1;
    1455           0 :                 b1 = CLAMP(ip[6]);
    1456           0 :                 wp[6] = (uint16_t)((b1 - b2) & mask);
    1457           0 :                 b2 = b1;
    1458           0 :                 a1 = CLAMP(ip[7]);
    1459           0 :                 wp[7] = (uint16_t)((a1 - a2) & mask);
    1460           0 :                 a2 = a1;
    1461           0 :                 wp += 4;
    1462           0 :                 ip += 4;
    1463             :             }
    1464             :         }
    1465             :         else
    1466             :         {
    1467           0 :             REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++)
    1468           0 :             n -= stride;
    1469           0 :             while (n > 0)
    1470             :             {
    1471           0 :                 REPEAT(stride,
    1472             :                        wp[0] = (uint16_t)((CLAMP(ip[0]) - CLAMP(ip[-stride])) &
    1473             :                                           mask);
    1474             :                        wp++; ip++)
    1475           0 :                 n -= stride;
    1476             :             }
    1477             :         }
    1478             :     }
    1479           0 : }
    1480             : 
    1481             : /*
    1482             :  * Encode a chunk of pixels.
    1483             :  */
    1484           0 : static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
    1485             : {
    1486             :     static const char module[] = "PixarLogEncode";
    1487           0 :     TIFFDirectory *td = &tif->tif_dir;
    1488           0 :     PixarLogState *sp = PixarLogEncoderState(tif);
    1489             :     tmsize_t i;
    1490             :     tmsize_t n;
    1491             :     tmsize_t llen;
    1492             :     unsigned short *up;
    1493             : 
    1494             :     (void)s;
    1495             : 
    1496           0 :     switch (sp->user_datafmt)
    1497             :     {
    1498           0 :         case PIXARLOGDATAFMT_FLOAT:
    1499           0 :             n = (tmsize_t)((unsigned long)cc /
    1500             :                            sizeof(float)); /* XXX float == 32 bits */
    1501           0 :             break;
    1502           0 :         case PIXARLOGDATAFMT_16BIT:
    1503             :         case PIXARLOGDATAFMT_12BITPICIO:
    1504             :         case PIXARLOGDATAFMT_11BITLOG:
    1505           0 :             n = (tmsize_t)((unsigned long)cc /
    1506             :                            sizeof(uint16_t)); /* XXX uint16_t == 16 bits */
    1507           0 :             break;
    1508           0 :         case PIXARLOGDATAFMT_8BIT:
    1509             :         case PIXARLOGDATAFMT_8BITABGR:
    1510           0 :             n = cc;
    1511           0 :             break;
    1512           0 :         default:
    1513           0 :             TIFFErrorExtR(tif, module,
    1514             :                           "%" PRIu16 " bit input not supported in PixarLog",
    1515           0 :                           td->td_bitspersample);
    1516           0 :             return 0;
    1517             :     }
    1518             : 
    1519             :     /* stride (≤ td_samplesperpixel, max 65535) × imagewidth: fits tmsize_t */
    1520           0 :     llen = (tmsize_t)sp->stride * td->td_imagewidth;
    1521             :     /* Check against the number of elements (of size uint16_t) of sp->tbuf */
    1522             :     tmsize_t max_n =
    1523           0 :         _TIFFMultiplySSize(tif, (tmsize_t)td->td_rowsperstrip, llen, module);
    1524           0 :     if (max_n == 0 || n > max_n)
    1525             :     {
    1526           0 :         TIFFErrorExtR(tif, module, "Too many input bytes provided");
    1527           0 :         return 0;
    1528             :     }
    1529             : 
    1530           0 :     for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen)
    1531             :     {
    1532           0 :         switch (sp->user_datafmt)
    1533             :         {
    1534           0 :             case PIXARLOGDATAFMT_FLOAT:
    1535           0 :                 horizontalDifferenceF(bp, llen, sp->stride, up, sp->FromLT2);
    1536           0 :                 bp += (unsigned long)llen * sizeof(float);
    1537           0 :                 break;
    1538           0 :             case PIXARLOGDATAFMT_16BIT:
    1539           0 :                 horizontalDifference16(bp, llen, sp->stride, up, sp->From14);
    1540           0 :                 bp += (unsigned long)llen * sizeof(uint16_t);
    1541           0 :                 break;
    1542           0 :             case PIXARLOGDATAFMT_8BIT:
    1543           0 :                 horizontalDifference8((unsigned char *)bp, llen, sp->stride, up,
    1544             :                                       sp->From8);
    1545           0 :                 bp += (unsigned long)llen * sizeof(unsigned char);
    1546           0 :                 break;
    1547           0 :             default:
    1548           0 :                 TIFFErrorExtR(tif, module,
    1549             :                               "%" PRIu16 " bit input not supported in PixarLog",
    1550           0 :                               td->td_bitspersample);
    1551           0 :                 return 0;
    1552             :         }
    1553             :     }
    1554             : 
    1555           0 :     sp->stream.next_in = (unsigned char *)sp->tbuf;
    1556             :     assert(sizeof(sp->stream.avail_in) == 4); /* if this assert gets raised,
    1557             :          we need to simplify this code to reflect a ZLib that is likely updated
    1558             :          to deal with 8byte memory sizes, though this code will respond
    1559             :          appropriately even before we simplify it */
    1560           0 :     sp->stream.avail_in = (uInt)((unsigned long)n * sizeof(uint16_t));
    1561           0 :     if ((sp->stream.avail_in / sizeof(uint16_t)) != (unsigned long)n)
    1562             :     {
    1563           0 :         TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
    1564           0 :         return (0);
    1565             :     }
    1566             : 
    1567             :     do
    1568             :     {
    1569           0 :         if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK)
    1570             :         {
    1571           0 :             TIFFErrorExtR(tif, module, "Encoder error: %s",
    1572           0 :                           sp->stream.msg ? sp->stream.msg : "(null)");
    1573           0 :             return (0);
    1574             :         }
    1575           0 :         if (sp->stream.avail_out == 0)
    1576             :         {
    1577           0 :             tif->tif_rawcc = tif->tif_rawdatasize;
    1578           0 :             if (!TIFFFlushData1(tif))
    1579           0 :                 return 0;
    1580           0 :             sp->stream.next_out = tif->tif_rawdata;
    1581           0 :             sp->stream.avail_out =
    1582           0 :                 (uInt)tif
    1583           0 :                     ->tif_rawdatasize; /* this is a safe typecast, as check is
    1584             :                                           made already in PixarLogPreEncode */
    1585             :         }
    1586           0 :     } while (sp->stream.avail_in > 0);
    1587           0 :     return (1);
    1588             : }
    1589             : 
    1590             : /*
    1591             :  * Finish off an encoded strip by flushing the last
    1592             :  * string and tacking on an End Of Information code.
    1593             :  */
    1594             : 
    1595           0 : static int PixarLogPostEncode(TIFF *tif)
    1596             : {
    1597             :     static const char module[] = "PixarLogPostEncode";
    1598           0 :     PixarLogState *sp = PixarLogEncoderState(tif);
    1599             :     int state;
    1600             : 
    1601           0 :     sp->stream.avail_in = 0;
    1602             : 
    1603             :     do
    1604             :     {
    1605           0 :         state = deflate(&sp->stream, Z_FINISH);
    1606           0 :         switch (state)
    1607             :         {
    1608           0 :             case Z_STREAM_END:
    1609             :             case Z_OK:
    1610           0 :                 if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
    1611             :                 {
    1612           0 :                     tif->tif_rawcc =
    1613           0 :                         tif->tif_rawdatasize - sp->stream.avail_out;
    1614           0 :                     if (!TIFFFlushData1(tif))
    1615           0 :                         return 0;
    1616           0 :                     sp->stream.next_out = tif->tif_rawdata;
    1617           0 :                     sp->stream.avail_out =
    1618           0 :                         (uInt)tif->tif_rawdatasize; /* this is a safe typecast,
    1619             :                                                        as check is made already
    1620             :                                                        in PixarLogPreEncode */
    1621             :                 }
    1622           0 :                 break;
    1623           0 :             default:
    1624           0 :                 TIFFErrorExtR(tif, module, "ZLib error: %s",
    1625           0 :                               sp->stream.msg ? sp->stream.msg : "(null)");
    1626           0 :                 return (0);
    1627             :         }
    1628           0 :     } while (state != Z_STREAM_END);
    1629           0 :     return (1);
    1630             : }
    1631             : 
    1632           0 : static void PixarLogClose(TIFF *tif)
    1633             : {
    1634           0 :     PixarLogState *sp = (PixarLogState *)tif->tif_data;
    1635           0 :     TIFFDirectory *td = &tif->tif_dir;
    1636             : 
    1637           0 :     assert(sp != 0);
    1638             :     /* In a really sneaky (and really incorrect, and untruthful, and
    1639             :      * troublesome, and error-prone) maneuver that completely goes against
    1640             :      * the spirit of TIFF, and breaks TIFF, on close, we covertly
    1641             :      * modify both bitspersample and sampleformat in the directory to
    1642             :      * indicate 8-bit linear.  This way, the decode "just works" even for
    1643             :      * readers that don't know about PixarLog, or how to set
    1644             :      * the PIXARLOGDATFMT pseudo-tag.
    1645             :      */
    1646             : 
    1647           0 :     if (sp->state & PLSTATE_INIT)
    1648             :     {
    1649             :         /* We test the state to avoid an issue such as in
    1650             :          * http://bugzilla.maptools.org/show_bug.cgi?id=2604
    1651             :          * What appends in that case is that the bitspersample is 1 and
    1652             :          * a TransferFunction is set. The size of the TransferFunction
    1653             :          * depends on 1<<bitspersample. So if we increase it, an access
    1654             :          * out of the buffer will happen at directory flushing.
    1655             :          * Another option would be to clear those targs.
    1656             :          */
    1657           0 :         td->td_bitspersample = 8;
    1658           0 :         td->td_sampleformat = SAMPLEFORMAT_UINT;
    1659             :     }
    1660           0 : }
    1661             : 
    1662           0 : static void PixarLogCleanup(TIFF *tif)
    1663             : {
    1664           0 :     PixarLogState *sp = (PixarLogState *)tif->tif_data;
    1665             : 
    1666           0 :     assert(sp != 0);
    1667             : 
    1668           0 :     (void)TIFFPredictorCleanup(tif);
    1669             : 
    1670           0 :     tif->tif_tagmethods.vgetfield = sp->vgetparent;
    1671           0 :     tif->tif_tagmethods.vsetfield = sp->vsetparent;
    1672             : 
    1673           0 :     if (sp->FromLT2)
    1674           0 :         _TIFFfreeExt(tif, sp->FromLT2);
    1675           0 :     if (sp->From14)
    1676           0 :         _TIFFfreeExt(tif, sp->From14);
    1677           0 :     if (sp->From8)
    1678           0 :         _TIFFfreeExt(tif, sp->From8);
    1679           0 :     if (sp->ToLinearF)
    1680           0 :         _TIFFfreeExt(tif, sp->ToLinearF);
    1681           0 :     if (sp->ToLinear16)
    1682           0 :         _TIFFfreeExt(tif, sp->ToLinear16);
    1683           0 :     if (sp->ToLinear8)
    1684           0 :         _TIFFfreeExt(tif, sp->ToLinear8);
    1685           0 :     if (sp->state & PLSTATE_INIT)
    1686             :     {
    1687           0 :         if (tif->tif_mode == O_RDONLY)
    1688           0 :             inflateEnd(&sp->stream);
    1689             :         else
    1690           0 :             deflateEnd(&sp->stream);
    1691             :     }
    1692           0 :     if (sp->tbuf)
    1693           0 :         _TIFFfreeExt(tif, sp->tbuf);
    1694           0 :     _TIFFfreeExt(tif, sp);
    1695           0 :     tif->tif_data = NULL;
    1696             : 
    1697           0 :     _TIFFSetDefaultCompressionState(tif);
    1698           0 : }
    1699             : 
    1700           0 : static int PixarLogVSetField(TIFF *tif, uint32_t tag, va_list ap)
    1701             : {
    1702             :     static const char module[] = "PixarLogVSetField";
    1703           0 :     PixarLogState *sp = (PixarLogState *)tif->tif_data;
    1704             :     int result;
    1705             : 
    1706           0 :     switch (tag)
    1707             :     {
    1708           0 :         case TIFFTAG_PIXARLOGQUALITY:
    1709           0 :             sp->quality = (int)va_arg(ap, int);
    1710           0 :             if (tif->tif_mode != O_RDONLY && (sp->state & PLSTATE_INIT))
    1711             :             {
    1712           0 :                 if (deflateParams(&sp->stream, sp->quality,
    1713             :                                   Z_DEFAULT_STRATEGY) != Z_OK)
    1714             :                 {
    1715           0 :                     TIFFErrorExtR(tif, module, "ZLib error: %s",
    1716           0 :                                   sp->stream.msg ? sp->stream.msg : "(null)");
    1717           0 :                     return (0);
    1718             :                 }
    1719             :             }
    1720           0 :             return (1);
    1721           0 :         case TIFFTAG_PIXARLOGDATAFMT:
    1722           0 :             sp->user_datafmt = (int)va_arg(ap, int);
    1723             :             /* Tweak the TIFF header so that the rest of libtiff knows what
    1724             :              * size of data will be passed between app and library, and
    1725             :              * assume that the app knows what it is doing and is not
    1726             :              * confused by these header manipulations...
    1727             :              */
    1728           0 :             switch (sp->user_datafmt)
    1729             :             {
    1730           0 :                 case PIXARLOGDATAFMT_8BIT:
    1731             :                 case PIXARLOGDATAFMT_8BITABGR:
    1732           0 :                     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
    1733           0 :                     TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
    1734           0 :                     break;
    1735           0 :                 case PIXARLOGDATAFMT_11BITLOG:
    1736           0 :                     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
    1737           0 :                     TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
    1738           0 :                     break;
    1739           0 :                 case PIXARLOGDATAFMT_12BITPICIO:
    1740           0 :                     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
    1741           0 :                     TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
    1742           0 :                     break;
    1743           0 :                 case PIXARLOGDATAFMT_16BIT:
    1744           0 :                     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
    1745           0 :                     TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
    1746           0 :                     break;
    1747           0 :                 case PIXARLOGDATAFMT_FLOAT:
    1748           0 :                     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
    1749           0 :                     TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT,
    1750             :                                  SAMPLEFORMAT_IEEEFP);
    1751           0 :                     break;
    1752           0 :                 default:
    1753           0 :                     break;
    1754             :             }
    1755             :             /*
    1756             :              * Must recalculate sizes should bits/sample change.
    1757             :              */
    1758           0 :             tif->tif_dir.td_tilesize =
    1759           0 :                 isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1);
    1760           0 :             tif->tif_dir.td_scanlinesize = TIFFScanlineSize(tif);
    1761           0 :             result = 1; /* NB: pseudo tag */
    1762           0 :             break;
    1763           0 :         default:
    1764           0 :             result = (*sp->vsetparent)(tif, tag, ap);
    1765             :     }
    1766           0 :     return (result);
    1767             : }
    1768             : 
    1769           0 : static int PixarLogVGetField(TIFF *tif, uint32_t tag, va_list ap)
    1770             : {
    1771           0 :     PixarLogState *sp = (PixarLogState *)tif->tif_data;
    1772             : 
    1773           0 :     switch (tag)
    1774             :     {
    1775           0 :         case TIFFTAG_PIXARLOGQUALITY:
    1776           0 :             *va_arg(ap, int *) = sp->quality;
    1777           0 :             break;
    1778           0 :         case TIFFTAG_PIXARLOGDATAFMT:
    1779           0 :             *va_arg(ap, int *) = sp->user_datafmt;
    1780           0 :             break;
    1781           0 :         default:
    1782           0 :             return (*sp->vgetparent)(tif, tag, ap);
    1783             :     }
    1784           0 :     return (1);
    1785             : }
    1786             : 
    1787             : static const TIFFField pixarlogFields[] = {
    1788             :     {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO,
    1789             :      FALSE, FALSE, "", NULL},
    1790             :     {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO,
    1791             :      FALSE, FALSE, "", NULL}};
    1792             : 
    1793           0 : static uint64_t PixarLogGetMaxCompressionRatio(TIFF *tif)
    1794             : {
    1795             :     (void)tif;
    1796             :     /* cf https://zlib.net/zlib_tech.html */
    1797           0 :     const uint64_t MAX_DEFLATE_RATIO = 1032;
    1798             : 
    1799             :     /* security margin as I don't understand what this codec does */
    1800           0 :     return MAX_DEFLATE_RATIO * (uint64_t)4;
    1801             : }
    1802             : 
    1803           0 : int TIFFInitPixarLog(TIFF *tif, int scheme)
    1804             : {
    1805             :     static const char module[] = "TIFFInitPixarLog";
    1806             : 
    1807             :     PixarLogState *sp;
    1808             : 
    1809             :     (void)scheme;
    1810           0 :     assert(scheme == COMPRESSION_PIXARLOG);
    1811             : 
    1812             :     /*
    1813             :      * Merge codec-specific tag information.
    1814             :      */
    1815           0 :     if (!_TIFFMergeFields(tif, pixarlogFields, TIFFArrayCount(pixarlogFields)))
    1816             :     {
    1817           0 :         TIFFErrorExtR(tif, module,
    1818             :                       "Merging PixarLog codec-specific tags failed");
    1819           0 :         return 0;
    1820             :     }
    1821             : 
    1822             :     /*
    1823             :      * Allocate state block so tag methods have storage to record values.
    1824             :      */
    1825           0 :     tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(PixarLogState));
    1826           0 :     if (tif->tif_data == NULL)
    1827           0 :         goto bad;
    1828           0 :     sp = (PixarLogState *)tif->tif_data;
    1829           0 :     _TIFFmemset(sp, 0, sizeof(*sp));
    1830           0 :     sp->stream.data_type = Z_BINARY;
    1831           0 :     sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN;
    1832             : 
    1833             :     /*
    1834             :      * Install codec methods.
    1835             :      */
    1836           0 :     tif->tif_fixuptags = PixarLogFixupTags;
    1837           0 :     tif->tif_setupdecode = PixarLogSetupDecode;
    1838           0 :     tif->tif_predecode = PixarLogPreDecode;
    1839           0 :     tif->tif_decoderow = PixarLogDecode;
    1840           0 :     tif->tif_decodestrip = PixarLogDecode;
    1841           0 :     tif->tif_decodetile = PixarLogDecode;
    1842           0 :     tif->tif_setupencode = PixarLogSetupEncode;
    1843           0 :     tif->tif_preencode = PixarLogPreEncode;
    1844           0 :     tif->tif_postencode = PixarLogPostEncode;
    1845           0 :     tif->tif_encoderow = PixarLogEncode;
    1846           0 :     tif->tif_encodestrip = PixarLogEncode;
    1847           0 :     tif->tif_encodetile = PixarLogEncode;
    1848           0 :     tif->tif_close = PixarLogClose;
    1849           0 :     tif->tif_cleanup = PixarLogCleanup;
    1850           0 :     tif->tif_getmaxcompressionratio = PixarLogGetMaxCompressionRatio;
    1851             : 
    1852             :     /* Override SetField so we can handle our private pseudo-tag */
    1853           0 :     sp->vgetparent = tif->tif_tagmethods.vgetfield;
    1854           0 :     tif->tif_tagmethods.vgetfield = PixarLogVGetField; /* hook for codec tags */
    1855           0 :     sp->vsetparent = tif->tif_tagmethods.vsetfield;
    1856           0 :     tif->tif_tagmethods.vsetfield = PixarLogVSetField; /* hook for codec tags */
    1857             : 
    1858             :     /* Default values for codec-specific fields */
    1859           0 :     sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */
    1860           0 :     sp->state = 0;
    1861             : 
    1862             :     /* we don't wish to use the predictor,
    1863             :      * the default is none, which predictor value 1
    1864             :      */
    1865           0 :     (void)TIFFPredictorInit(tif);
    1866             : 
    1867             :     /*
    1868             :      * build the companding tables
    1869             :      */
    1870           0 :     PixarLogMakeTables(tif, sp);
    1871             : 
    1872           0 :     return (1);
    1873           0 : bad:
    1874           0 :     TIFFErrorExtR(tif, module, "No space for PixarLog state block");
    1875           0 :     return (0);
    1876             : }
    1877             : #endif /* PIXARLOG_SUPPORT */

Generated by: LCOV version 1.14