Coverage Report

Created: 2026-09-14 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/gtiff/libtiff/tif_pixarlog.c
Line
Count
Source
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
0
#define TSIZE 2048   /* decode table size (11-bit tokens) */
100
0
#define TSIZEP1 2049 /* Plus one for slop */
101
0
#define ONE 1250     /* token value of 1.0 exactly */
102
0
#define RATIO 1.004  /* nominal ratio for log part */
103
104
0
#define CODE_MASK 0x7ff /* 11 bits. */
105
106
static float Fltsize;
107
static float LogK1, LogK2;
108
109
#define REPEAT(n, op)                                                          \
110
0
    {                                                                          \
111
0
        int i;                                                                 \
112
0
        i = n;                                                                 \
113
0
        do                                                                     \
114
0
        {                                                                      \
115
0
            i--;                                                               \
116
0
            op;                                                                \
117
0
        } while (i > 0);                                                       \
118
0
    }
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
static float PixarLogLoadFloatNativeUnaligned(const uint8_t *cp)
128
0
{
129
0
    float v;
130
0
    memcpy(&v, cp, sizeof(v));
131
0
    return v;
132
0
}
133
134
static void PixarLogStoreFloatNativeUnaligned(uint8_t *cp, float v)
135
0
{
136
0
    memcpy(cp, &v, sizeof(v));
137
0
}
138
139
static uint16_t PixarLogLoad16NativeUnaligned(const uint8_t *cp)
140
0
{
141
0
    uint16_t v;
142
0
    memcpy(&v, cp, sizeof(v));
143
0
    return v;
144
0
}
145
146
static void PixarLogStore16NativeUnaligned(uint8_t *cp, uint16_t v)
147
0
{
148
0
    memcpy(cp, &v, sizeof(v));
149
0
}
150
151
static void horizontalAccumulateF(uint16_t *wp, tmsize_t n, int stride,
152
                                  uint8_t *op, float *ToLinearF)
153
0
{
154
0
    unsigned int cr, cg, cb, ca, mask;
155
0
    float t0, t1, t2, t3;
156
157
0
    if (n >= stride)
158
0
    {
159
0
        mask = CODE_MASK;
160
0
        if (stride == 3)
161
0
        {
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
0
            {
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
0
            }
181
0
        }
182
0
        else if (stride == 4)
183
0
        {
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
0
            {
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
0
            }
207
0
        }
208
0
        else
209
0
        {
210
0
            REPEAT(stride,
211
0
                   PixarLogStoreFloatNativeUnaligned(op, ToLinearF[*wp & mask]);
212
0
                   wp++; op += sizeof(float))
213
0
            n -= stride;
214
0
            while (n > 0)
215
0
            {
216
0
                REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
217
0
                       PixarLogStoreFloatNativeUnaligned(op,
218
0
                                                         ToLinearF[*wp & mask]);
219
0
                       wp++; op += sizeof(float))
220
0
                n -= stride;
221
0
            }
222
0
        }
223
0
    }
224
0
}
225
226
static void horizontalAccumulate12(uint16_t *wp, tmsize_t n, int stride,
227
                                   uint8_t *op, float *ToLinearF)
228
0
{
229
0
    unsigned int cr, cg, cb, ca, mask;
230
0
    float t0, t1, t2, t3;
231
232
0
#define SCALE12 2048.0f
233
0
#define CLAMP12(t) (((t) < 3071) ? (int16_t)(uint16_t)(t) : (int16_t)3071)
234
235
0
    if (n >= stride)
236
0
    {
237
0
        mask = CODE_MASK;
238
0
        if (stride == 3)
239
0
        {
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
0
            {
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
0
            }
263
0
        }
264
0
        else if (stride == 4)
265
0
        {
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
0
            {
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
0
            }
295
0
        }
296
0
        else
297
0
        {
298
0
            REPEAT(stride, t0 = ToLinearF[*wp & mask] * SCALE12;
299
0
                   PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
300
0
                   wp++; op += sizeof(uint16_t))
301
0
            n -= stride;
302
0
            while (n > 0)
303
0
            {
304
0
                REPEAT(
305
0
                    stride, *wp = (uint16_t)(*wp + wp[-stride]);
306
0
                    t0 = ToLinearF[*wp & mask] * SCALE12;
307
0
                    PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
308
0
                    wp++; op += sizeof(uint16_t))
309
0
                n -= stride;
310
0
            }
311
0
        }
312
0
    }
313
0
}
314
315
static void horizontalAccumulate16(uint16_t *wp, tmsize_t n, int stride,
316
                                   uint8_t *op, uint16_t *ToLinear16)
317
0
{
318
0
    unsigned int cr, cg, cb, ca, mask;
319
320
0
    if (n >= stride)
321
0
    {
322
0
        mask = CODE_MASK;
323
0
        if (stride == 3)
324
0
        {
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
0
            {
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
0
                    op + 2 * sizeof(uint16_t),
342
0
                    ToLinear16[(cb += wp[2]) & mask]);
343
0
            }
344
0
        }
345
0
        else if (stride == 4)
346
0
        {
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
0
            {
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
0
                    op + 2 * sizeof(uint16_t),
366
0
                    ToLinear16[(cb += wp[2]) & mask]);
367
0
                PixarLogStore16NativeUnaligned(
368
0
                    op + 3 * sizeof(uint16_t),
369
0
                    ToLinear16[(ca += wp[3]) & mask]);
370
0
            }
371
0
        }
372
0
        else
373
0
        {
374
0
            REPEAT(stride,
375
0
                   PixarLogStore16NativeUnaligned(op, ToLinear16[*wp & mask]);
376
0
                   wp++; op += sizeof(uint16_t))
377
0
            n -= stride;
378
0
            while (n > 0)
379
0
            {
380
0
                REPEAT(
381
0
                    stride, *wp = (uint16_t)(*wp + wp[-stride]);
382
0
                    PixarLogStore16NativeUnaligned(op, ToLinear16[*wp & mask]);
383
0
                    wp++; op += sizeof(uint16_t))
384
0
                n -= stride;
385
0
            }
386
0
        }
387
0
    }
388
0
}
389
390
/*
391
 * Returns the log encoded 11-bit values with the horizontal
392
 * differencing undone.
393
 */
394
static void horizontalAccumulate11(uint16_t *wp, tmsize_t n, int stride,
395
                                   uint8_t *op)
396
0
{
397
0
    unsigned int cr, cg, cb, ca, mask;
398
399
0
    if (n >= stride)
400
0
    {
401
0
        mask = CODE_MASK;
402
0
        if (stride == 3)
403
0
        {
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
0
            {
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
0
                    op + 2 * sizeof(uint16_t),
422
0
                    (uint16_t)((cb += wp[2]) & mask));
423
0
            }
424
0
        }
425
0
        else if (stride == 4)
426
0
        {
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
0
            {
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
0
                    op + 2 * sizeof(uint16_t),
447
0
                    (uint16_t)((cb += wp[2]) & mask));
448
0
                PixarLogStore16NativeUnaligned(
449
0
                    op + 3 * sizeof(uint16_t),
450
0
                    (uint16_t)((ca += wp[3]) & mask));
451
0
            }
452
0
        }
453
0
        else
454
0
        {
455
0
            REPEAT(stride,
456
0
                   PixarLogStore16NativeUnaligned(op, (uint16_t)(*wp & mask));
457
0
                   wp++; op += sizeof(uint16_t))
458
0
            n -= stride;
459
0
            while (n > 0)
460
0
            {
461
0
                REPEAT(
462
0
                    stride, *wp = (uint16_t)(*wp + wp[-stride]);
463
0
                    PixarLogStore16NativeUnaligned(op, (uint16_t)(*wp & mask));
464
0
                    wp++; op += sizeof(uint16_t))
465
0
                n -= stride;
466
0
            }
467
0
        }
468
0
    }
469
0
}
470
471
static void horizontalAccumulate8(uint16_t *wp, tmsize_t n, int stride,
472
                                  unsigned char *op, unsigned char *ToLinear8)
473
0
{
474
0
    unsigned int cr, cg, cb, ca, mask;
475
476
0
    if (n >= stride)
477
0
    {
478
0
        mask = CODE_MASK;
479
0
        if (stride == 3)
480
0
        {
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
0
            {
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
0
            }
494
0
        }
495
0
        else if (stride == 4)
496
0
        {
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
0
            {
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
0
            }
512
0
        }
513
0
        else
514
0
        {
515
0
            REPEAT(stride, *op = ToLinear8[*wp & mask]; wp++; op++)
516
0
            n -= stride;
517
0
            while (n > 0)
518
0
            {
519
0
                REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
520
0
                       *op = ToLinear8[*wp & mask]; wp++; op++)
521
0
                n -= stride;
522
0
            }
523
0
        }
524
0
    }
525
0
}
526
527
static void horizontalAccumulate8abgr(uint16_t *wp, tmsize_t n, int stride,
528
                                      unsigned char *op,
529
                                      unsigned char *ToLinear8)
530
0
{
531
0
    unsigned int cr, cg, cb, ca, mask;
532
0
    unsigned char t0, t1, t2, t3;
533
534
0
    if (n >= stride)
535
0
    {
536
0
        mask = CODE_MASK;
537
0
        if (stride == 3)
538
0
        {
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
0
            {
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
0
            }
560
0
        }
561
0
        else if (stride == 4)
562
0
        {
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
0
            {
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
0
            }
586
0
        }
587
0
        else
588
0
        {
589
0
            REPEAT(stride, *op = ToLinear8[*wp & mask]; wp++; op++)
590
0
            n -= stride;
591
0
            while (n > 0)
592
0
            {
593
0
                REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
594
0
                       *op = ToLinear8[*wp & mask]; wp++; op++)
595
0
                n -= stride;
596
0
            }
597
0
        }
598
0
    }
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
0
#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
static int PixarLogMakeTables(TIFF *tif, PixarLogState *sp)
630
0
{
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
0
    int nlin, lt2size;
644
0
    int i, j;
645
0
    double b, c, linstep, v;
646
0
    float *ToLinearF;
647
0
    uint16_t *ToLinear16;
648
0
    unsigned char *ToLinear8;
649
0
    uint16_t *FromLT2;
650
0
    uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */
651
0
    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
0
    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
0
    {
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
0
    }
693
694
0
    j = 0;
695
696
0
    for (i = 0; i < nlin; i++)
697
0
    {
698
0
        v = i * linstep;
699
0
        ToLinearF[j++] = (float)v;
700
0
    }
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
0
    {
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
0
    }
714
715
0
    j = 0;
716
0
    for (i = 0; i < lt2size; i++)
717
0
    {
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
0
    }
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
0
    {
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
0
    }
737
738
0
    j = 0;
739
0
    for (i = 0; i < 256; i++)
740
0
    {
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
0
    }
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
0
}
758
759
0
#define PixarLogDecoderState(tif) ((PixarLogState *)(tif)->tif_data)
760
0
#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
0
#define PIXARLOGDATAFMT_UNKNOWN -1
766
767
static int PixarLogGuessDataFmt(TIFFDirectory *td)
768
0
{
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
0
    {
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
0
    }
800
801
0
    return guess;
802
0
}
803
804
static tmsize_t multiply_ms(tmsize_t m1, tmsize_t m2)
805
0
{
806
0
    return _TIFFMultiplySSize(NULL, m1, m2, NULL);
807
0
}
808
809
static tmsize_t add_ms(tmsize_t m1, tmsize_t m2)
810
0
{
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
0
}
820
821
static int PixarLogFixupTags(TIFF *tif)
822
0
{
823
0
    (void)tif;
824
0
    return (1);
825
0
}
826
827
static int PixarLogSetupDecode(TIFF *tif)
828
0
{
829
0
    static const char module[] = "PixarLogSetupDecode";
830
0
    TIFFDirectory *td = &tif->tif_dir;
831
0
    PixarLogState *sp = PixarLogDecoderState(tif);
832
0
    tmsize_t tbuf_size;
833
0
    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
0
                                                    : 1);
856
0
    tbuf_size = multiply_ms(
857
0
        multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), strip_height),
858
0
        sizeof(uint16_t));
859
    /* add one more stride in case input ends mid-stride */
860
0
    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
0
    {
873
0
        _TIFFfreeExt(tif, sp->tbuf);
874
0
        sp->tbuf = NULL;
875
0
        sp->tbuf_size = 0;
876
0
        TIFFErrorExtR(tif, module,
877
0
                      "PixarLog compression can't handle bits depth/data "
878
0
                      "format combination (depth: %" PRIu16 ")",
879
0
                      td->td_bitspersample);
880
0
        return (0);
881
0
    }
882
883
0
    if (inflateInit(&sp->stream) != Z_OK)
884
0
    {
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
0
    }
892
0
    else
893
0
    {
894
0
        sp->state |= PLSTATE_INIT;
895
0
        return (1);
896
0
    }
897
0
}
898
899
/*
900
 * Setup state for decoding a strip.
901
 */
902
static int PixarLogPreDecode(TIFF *tif, uint16_t s)
903
0
{
904
0
    static const char module[] = "PixarLogPreDecode";
905
0
    PixarLogState *sp = PixarLogDecoderState(tif);
906
907
0
    (void)s;
908
0
    assert(sp != NULL);
909
0
    sp->stream.next_in = tif->tif_rawdata;
910
0
    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
0
    {
917
0
        TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
918
0
        return (0);
919
0
    }
920
0
    return (inflateReset(&sp->stream) == Z_OK);
921
0
}
922
923
static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
924
0
{
925
0
    static const char module[] = "PixarLogDecode";
926
0
    TIFFDirectory *td = &tif->tif_dir;
927
0
    PixarLogState *sp = PixarLogDecoderState(tif);
928
0
    tmsize_t i;
929
0
    tmsize_t nsamples;
930
0
    tmsize_t llen;
931
0
    uint16_t *up;
932
933
0
    switch (sp->user_datafmt)
934
0
    {
935
0
        case PIXARLOGDATAFMT_FLOAT:
936
0
            nsamples = (tmsize_t)((uint64_t)occ /
937
0
                                  sizeof(float)); /* XXX float == 32 bits */
938
0
            break;
939
0
        case PIXARLOGDATAFMT_16BIT:
940
0
        case PIXARLOGDATAFMT_12BITPICIO:
941
0
        case PIXARLOGDATAFMT_11BITLOG:
942
0
            nsamples =
943
0
                (tmsize_t)((uint64_t)occ /
944
0
                           sizeof(uint16_t)); /* XXX uint16_t == 16 bits */
945
0
            break;
946
0
        case PIXARLOGDATAFMT_8BIT:
947
0
        case PIXARLOGDATAFMT_8BITABGR:
948
0
            nsamples = occ;
949
0
            break;
950
0
        default:
951
0
            TIFFErrorExtR(tif, module,
952
0
                          "%" 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
0
    }
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
0
    {
964
        /* imagewidth × 4: fits tmsize_t (imagewidth is uint32) */
965
0
        tmsize_t required = (tmsize_t)td->td_imagewidth * 4;
966
0
        tmsize_t max_rows;
967
0
        tmsize_t max_nsamples;
968
969
        /*
970
         * Ensure at least one expanded output row fits.
971
         */
972
0
        if (occ < required)
973
0
        {
974
0
            TIFFErrorExtR(tif, module,
975
0
                          "Output buffer too small for PixarLog ABGR data");
976
0
            memset(op, 0, (size_t)occ);
977
0
            return (0);
978
0
        }
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
0
        {
986
0
            TIFFErrorExtR(
987
0
                tif, module,
988
0
                "Fractional scanline not supported for PixarLog ABGR data");
989
0
            memset(op, 0, (size_t)occ);
990
0
            return (0);
991
0
        }
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
0
        {
1003
0
            TIFFErrorExtR(tif, module,
1004
0
                          "Output buffer too small for PixarLog ABGR data");
1005
0
            memset(op, 0, (size_t)occ);
1006
0
            return (0);
1007
0
        }
1008
0
    }
1009
1010
0
    (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
0
    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
0
    {
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
0
    }
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
0
    {
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
0
    }
1035
0
    do
1036
0
    {
1037
0
        int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
1038
0
        if (state == Z_STREAM_END)
1039
0
        {
1040
0
            break; /* XXX */
1041
0
        }
1042
0
        if (state == Z_DATA_ERROR)
1043
0
        {
1044
0
            TIFFErrorExtR(tif, module,
1045
0
                          "Decoding error at scanline %" PRIu32 ", %s",
1046
0
                          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
0
        }
1051
0
        if (state != Z_OK)
1052
0
        {
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
0
        }
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
0
    {
1063
0
        TIFFErrorExtR(tif, module,
1064
0
                      "Not enough data at scanline %" PRIu32
1065
0
                      " (short %u bytes)",
1066
0
                      tif->tif_dir.td_row, sp->stream.avail_out);
1067
0
        memset(op, 0, (size_t)occ);
1068
0
        return (0);
1069
0
    }
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
0
    {
1086
0
        TIFFWarningExtR(tif, module,
1087
0
                        "stride %" TIFF_SSIZE_FORMAT
1088
0
                        " is not a multiple of sample count, "
1089
0
                        "%" TIFF_SSIZE_FORMAT ", data truncated.",
1090
0
                        llen, nsamples);
1091
0
        nsamples -= nsamples % llen;
1092
0
    }
1093
1094
0
    for (i = 0; i < nsamples; i += llen, up += llen)
1095
0
    {
1096
0
        switch (sp->user_datafmt)
1097
0
        {
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
0
                                       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
0
                                      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
0
                                          (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
0
                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
0
        }
1137
0
    }
1138
1139
0
    return (1);
1140
0
}
1141
1142
static int PixarLogSetupEncode(TIFF *tif)
1143
0
{
1144
0
    static const char module[] = "PixarLogSetupEncode";
1145
0
    TIFFDirectory *td = &tif->tif_dir;
1146
0
    PixarLogState *sp = PixarLogEncoderState(tif);
1147
0
    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
0
                                                    : 1);
1156
0
    tbuf_size =
1157
0
        multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
1158
0
                                td->td_rowsperstrip),
1159
0
                    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
0
    {
1170
0
        TIFFErrorExtR(tif, module,
1171
0
                      "PixarLog compression can't handle %" PRIu16
1172
0
                      " bit linear encodings",
1173
0
                      td->td_bitspersample);
1174
0
        return (0);
1175
0
    }
1176
1177
0
    if (deflateInit(&sp->stream, sp->quality) != Z_OK)
1178
0
    {
1179
0
        TIFFErrorExtR(tif, module, "%s",
1180
0
                      sp->stream.msg ? sp->stream.msg : "(null)");
1181
0
        return (0);
1182
0
    }
1183
0
    else
1184
0
    {
1185
0
        sp->state |= PLSTATE_INIT;
1186
0
        return (1);
1187
0
    }
1188
0
}
1189
1190
/*
1191
 * Reset encoding state at the start of a strip.
1192
 */
1193
static int PixarLogPreEncode(TIFF *tif, uint16_t s)
1194
0
{
1195
0
    static const char module[] = "PixarLogPreEncode";
1196
0
    PixarLogState *sp = PixarLogEncoderState(tif);
1197
1198
0
    (void)s;
1199
0
    assert(sp != NULL);
1200
0
    sp->stream.next_out = tif->tif_rawdata;
1201
0
    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
0
    {
1208
0
        TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
1209
0
        return (0);
1210
0
    }
1211
0
    return (deflateReset(&sp->stream) == Z_OK);
1212
0
}
1213
1214
static void horizontalDifferenceF(const uint8_t *ip, tmsize_t n, int stride,
1215
                                  uint16_t *wp, uint16_t *FromLT2)
1216
0
{
1217
0
    int32_t r1, g1, b1, a1, r2, g2, b2, a2, mask;
1218
0
    float fltsize = Fltsize;
1219
1220
0
#define CLAMP(v)                                                               \
1221
0
    ((v < (float)0.)   ? 0                                                     \
1222
0
     : (v < (float)2.) ? FromLT2[(int)(v * fltsize)]                           \
1223
0
     : (v > (float)24.2)                                                       \
1224
0
         ? 2047                                                                \
1225
0
         : (double)LogK1 * log((double)v * (double)LogK2) + 0.5)
1226
1227
0
    mask = CODE_MASK;
1228
0
    if (n >= stride)
1229
0
    {
1230
0
        if (stride == 3)
1231
0
        {
1232
0
            r2 = wp[0] = (uint16_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
1233
0
            g2 = wp[1] = (uint16_t)CLAMP(
1234
0
                PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1235
0
            b2 = wp[2] = (uint16_t)CLAMP(
1236
0
                PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1237
0
            n -= 3;
1238
0
            while (n > 0)
1239
0
            {
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
0
                    PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1248
0
                wp[1] = (uint16_t)((g1 - g2) & mask);
1249
0
                g2 = g1;
1250
0
                b1 = (int32_t)CLAMP(
1251
0
                    PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1252
0
                wp[2] = (uint16_t)((b1 - b2) & mask);
1253
0
                b2 = b1;
1254
0
            }
1255
0
        }
1256
0
        else if (stride == 4)
1257
0
        {
1258
0
            r2 = wp[0] = (uint16_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
1259
0
            g2 = wp[1] = (uint16_t)CLAMP(
1260
0
                PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1261
0
            b2 = wp[2] = (uint16_t)CLAMP(
1262
0
                PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1263
0
            a2 = wp[3] = (uint16_t)CLAMP(
1264
0
                PixarLogLoadFloatNativeUnaligned(ip + 3 * sizeof(float)));
1265
0
            n -= 4;
1266
0
            while (n > 0)
1267
0
            {
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
0
                    PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1276
0
                wp[1] = (uint16_t)((g1 - g2) & mask);
1277
0
                g2 = g1;
1278
0
                b1 = (int32_t)CLAMP(
1279
0
                    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
0
                    PixarLogLoadFloatNativeUnaligned(ip + 3 * sizeof(float)));
1284
0
                wp[3] = (uint16_t)((a1 - a2) & mask);
1285
0
                a2 = a1;
1286
0
            }
1287
0
        }
1288
0
        else
1289
0
        {
1290
0
            REPEAT(stride, wp[0] = (uint16_t)CLAMP(
1291
0
                               PixarLogLoadFloatNativeUnaligned(ip));
1292
0
                   wp++; ip += sizeof(float))
1293
0
            n -= stride;
1294
0
            while (n > 0)
1295
0
            {
1296
0
                REPEAT(
1297
0
                    stride,
1298
0
                    wp[0] =
1299
0
                        (uint16_t)(((int32_t)CLAMP(
1300
0
                                        PixarLogLoadFloatNativeUnaligned(ip)) -
1301
0
                                    (int32_t)CLAMP(
1302
0
                                        PixarLogLoadFloatNativeUnaligned(
1303
0
                                            ip -
1304
0
                                            (tmsize_t)stride *
1305
0
                                                (tmsize_t)sizeof(float)))) &
1306
0
                                   mask);
1307
0
                    wp++; ip += sizeof(float))
1308
0
                n -= stride;
1309
0
            }
1310
0
        }
1311
0
    }
1312
0
}
1313
1314
static void horizontalDifference16(const uint8_t *ip, tmsize_t n, int stride,
1315
                                   unsigned short *wp, uint16_t *From14)
1316
0
{
1317
0
    int r1, g1, b1, a1, r2, g2, b2, a2, mask;
1318
1319
/* assumption is unsigned pixel values */
1320
0
#undef CLAMP
1321
0
#define CLAMP(v) From14[(v) >> 2]
1322
1323
0
    mask = CODE_MASK;
1324
0
    if (n >= stride)
1325
0
    {
1326
0
        if (stride == 3)
1327
0
        {
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
0
            {
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
0
                    PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
1348
0
                wp[2] = (uint16_t)((b1 - b2) & mask);
1349
0
                b2 = b1;
1350
0
            }
1351
0
        }
1352
0
        else if (stride == 4)
1353
0
        {
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
0
            {
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
0
                    PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
1376
0
                wp[2] = (uint16_t)((b1 - b2) & mask);
1377
0
                b2 = b1;
1378
0
                a1 = CLAMP(
1379
0
                    PixarLogLoad16NativeUnaligned(ip + 3 * sizeof(uint16_t)));
1380
0
                wp[3] = (uint16_t)((a1 - a2) & mask);
1381
0
                a2 = a1;
1382
0
            }
1383
0
        }
1384
0
        else
1385
0
        {
1386
0
            REPEAT(stride, wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
1387
0
                   wp++; ip += sizeof(uint16_t))
1388
0
            n -= stride;
1389
0
            while (n > 0)
1390
0
            {
1391
0
                REPEAT(
1392
0
                    stride,
1393
0
                    wp[0] =
1394
0
                        (uint16_t)((CLAMP(PixarLogLoad16NativeUnaligned(ip)) -
1395
0
                                    CLAMP(PixarLogLoad16NativeUnaligned(
1396
0
                                        ip - (tmsize_t)stride *
1397
0
                                                 (tmsize_t)sizeof(uint16_t)))) &
1398
0
                                   mask);
1399
0
                    wp++; ip += sizeof(uint16_t))
1400
0
                n -= stride;
1401
0
            }
1402
0
        }
1403
0
    }
1404
0
}
1405
1406
static void horizontalDifference8(unsigned char *ip, tmsize_t n, int stride,
1407
                                  unsigned short *wp, uint16_t *From8)
1408
0
{
1409
0
    int r1, g1, b1, a1, r2, g2, b2, a2, mask;
1410
1411
0
#undef CLAMP
1412
0
#define CLAMP(v) (From8[(v)])
1413
1414
0
    mask = CODE_MASK;
1415
0
    if (n >= stride)
1416
0
    {
1417
0
        if (stride == 3)
1418
0
        {
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
0
            {
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
0
            }
1438
0
        }
1439
0
        else if (stride == 4)
1440
0
        {
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
0
            {
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
0
            }
1464
0
        }
1465
0
        else
1466
0
        {
1467
0
            REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++)
1468
0
            n -= stride;
1469
0
            while (n > 0)
1470
0
            {
1471
0
                REPEAT(stride,
1472
0
                       wp[0] = (uint16_t)((CLAMP(ip[0]) - CLAMP(ip[-stride])) &
1473
0
                                          mask);
1474
0
                       wp++; ip++)
1475
0
                n -= stride;
1476
0
            }
1477
0
        }
1478
0
    }
1479
0
}
1480
1481
/*
1482
 * Encode a chunk of pixels.
1483
 */
1484
static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
1485
0
{
1486
0
    static const char module[] = "PixarLogEncode";
1487
0
    TIFFDirectory *td = &tif->tif_dir;
1488
0
    PixarLogState *sp = PixarLogEncoderState(tif);
1489
0
    tmsize_t i;
1490
0
    tmsize_t n;
1491
0
    tmsize_t llen;
1492
0
    unsigned short *up;
1493
1494
0
    (void)s;
1495
1496
0
    switch (sp->user_datafmt)
1497
0
    {
1498
0
        case PIXARLOGDATAFMT_FLOAT:
1499
0
            n = (tmsize_t)((unsigned long)cc /
1500
0
                           sizeof(float)); /* XXX float == 32 bits */
1501
0
            break;
1502
0
        case PIXARLOGDATAFMT_16BIT:
1503
0
        case PIXARLOGDATAFMT_12BITPICIO:
1504
0
        case PIXARLOGDATAFMT_11BITLOG:
1505
0
            n = (tmsize_t)((unsigned long)cc /
1506
0
                           sizeof(uint16_t)); /* XXX uint16_t == 16 bits */
1507
0
            break;
1508
0
        case PIXARLOGDATAFMT_8BIT:
1509
0
        case PIXARLOGDATAFMT_8BITABGR:
1510
0
            n = cc;
1511
0
            break;
1512
0
        default:
1513
0
            TIFFErrorExtR(tif, module,
1514
0
                          "%" PRIu16 " bit input not supported in PixarLog",
1515
0
                          td->td_bitspersample);
1516
0
            return 0;
1517
0
    }
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
0
    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
0
    {
1526
0
        TIFFErrorExtR(tif, module, "Too many input bytes provided");
1527
0
        return 0;
1528
0
    }
1529
1530
0
    for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen)
1531
0
    {
1532
0
        switch (sp->user_datafmt)
1533
0
        {
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
0
                                      sp->From8);
1545
0
                bp += (unsigned long)llen * sizeof(unsigned char);
1546
0
                break;
1547
0
            default:
1548
0
                TIFFErrorExtR(tif, module,
1549
0
                              "%" PRIu16 " bit input not supported in PixarLog",
1550
0
                              td->td_bitspersample);
1551
0
                return 0;
1552
0
        }
1553
0
    }
1554
1555
0
    sp->stream.next_in = (unsigned char *)sp->tbuf;
1556
0
    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
0
    {
1563
0
        TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
1564
0
        return (0);
1565
0
    }
1566
1567
0
    do
1568
0
    {
1569
0
        if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK)
1570
0
        {
1571
0
            TIFFErrorExtR(tif, module, "Encoder error: %s",
1572
0
                          sp->stream.msg ? sp->stream.msg : "(null)");
1573
0
            return (0);
1574
0
        }
1575
0
        if (sp->stream.avail_out == 0)
1576
0
        {
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
0
        }
1586
0
    } while (sp->stream.avail_in > 0);
1587
0
    return (1);
1588
0
}
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
static int PixarLogPostEncode(TIFF *tif)
1596
0
{
1597
0
    static const char module[] = "PixarLogPostEncode";
1598
0
    PixarLogState *sp = PixarLogEncoderState(tif);
1599
0
    int state;
1600
1601
0
    sp->stream.avail_in = 0;
1602
1603
0
    do
1604
0
    {
1605
0
        state = deflate(&sp->stream, Z_FINISH);
1606
0
        switch (state)
1607
0
        {
1608
0
            case Z_STREAM_END:
1609
0
            case Z_OK:
1610
0
                if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
1611
0
                {
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
0
                }
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
0
        }
1628
0
    } while (state != Z_STREAM_END);
1629
0
    return (1);
1630
0
}
1631
1632
static void PixarLogClose(TIFF *tif)
1633
0
{
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
0
    {
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
0
    }
1660
0
}
1661
1662
static void PixarLogCleanup(TIFF *tif)
1663
0
{
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
0
    {
1687
0
        if (tif->tif_mode == O_RDONLY)
1688
0
            inflateEnd(&sp->stream);
1689
0
        else
1690
0
            deflateEnd(&sp->stream);
1691
0
    }
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
static int PixarLogVSetField(TIFF *tif, uint32_t tag, va_list ap)
1701
0
{
1702
0
    static const char module[] = "PixarLogVSetField";
1703
0
    PixarLogState *sp = (PixarLogState *)tif->tif_data;
1704
0
    int result;
1705
1706
0
    switch (tag)
1707
0
    {
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
0
            {
1712
0
                if (deflateParams(&sp->stream, sp->quality,
1713
0
                                  Z_DEFAULT_STRATEGY) != Z_OK)
1714
0
                {
1715
0
                    TIFFErrorExtR(tif, module, "ZLib error: %s",
1716
0
                                  sp->stream.msg ? sp->stream.msg : "(null)");
1717
0
                    return (0);
1718
0
                }
1719
0
            }
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
0
            {
1730
0
                case PIXARLOGDATAFMT_8BIT:
1731
0
                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
0
                                 SAMPLEFORMAT_IEEEFP);
1751
0
                    break;
1752
0
                default:
1753
0
                    break;
1754
0
            }
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
0
    }
1766
0
    return (result);
1767
0
}
1768
1769
static int PixarLogVGetField(TIFF *tif, uint32_t tag, va_list ap)
1770
0
{
1771
0
    PixarLogState *sp = (PixarLogState *)tif->tif_data;
1772
1773
0
    switch (tag)
1774
0
    {
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
0
    }
1784
0
    return (1);
1785
0
}
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
static uint64_t PixarLogGetMaxCompressionRatio(TIFF *tif)
1794
0
{
1795
0
    (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
0
}
1802
1803
int TIFFInitPixarLog(TIFF *tif, int scheme)
1804
0
{
1805
0
    static const char module[] = "TIFFInitPixarLog";
1806
1807
0
    PixarLogState *sp;
1808
1809
0
    (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
0
    {
1817
0
        TIFFErrorExtR(tif, module,
1818
0
                      "Merging PixarLog codec-specific tags failed");
1819
0
        return 0;
1820
0
    }
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
0
}
1877
#endif /* PIXARLOG_SUPPORT */