Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/gtiff/libtiff/tif_lzma.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2010, Andrey Kiselev <dron@ak4719.spb.edu>
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software and
5
 * its documentation for any purpose is hereby granted without fee, provided
6
 * that (i) the above copyright notices and this permission notice appear in
7
 * all copies of the software and related documentation, and (ii) the names of
8
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
9
 * publicity relating to the software without the specific, prior written
10
 * permission of Sam Leffler and Silicon Graphics.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
13
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
14
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
15
 *
16
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
17
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
18
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
20
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21
 * OF THIS SOFTWARE.
22
 */
23
24
#include "tiffiop.h"
25
#ifdef LZMA_SUPPORT
26
/*
27
 * TIFF Library.
28
 *
29
 * LZMA2 Compression Support
30
 *
31
 * You need an LZMA2 SDK to link with. See http://tukaani.org/xz/ for details.
32
 *
33
 * The codec is derived from ZLIB codec (tif_zip.c).
34
 */
35
36
#include "lzma.h"
37
#include "tif_predict.h"
38
39
#include <stdio.h>
40
41
/*
42
 * State block for each open TIFF file using LZMA2 compression/decompression.
43
 */
44
typedef struct
45
{
46
    TIFFPredictorState predict;
47
    int read_error; /* whether a read error has occurred, and which should cause
48
                       further reads in the same strip/tile to be aborted */
49
    lzma_stream stream;
50
    lzma_filter filters[LZMA_FILTERS_MAX + 1];
51
    lzma_options_delta opt_delta; /* delta filter options */
52
    lzma_options_lzma opt_lzma;   /* LZMA2 filter options */
53
    int preset;                   /* compression level */
54
    lzma_check check;             /* type of the integrity check */
55
    int state;                    /* state flags */
56
0
#define LSTATE_INIT_DECODE 0x01
57
0
#define LSTATE_INIT_ENCODE 0x02
58
59
    TIFFVGetMethod vgetparent; /* super-class method */
60
    TIFFVSetMethod vsetparent; /* super-class method */
61
} LZMAState;
62
63
0
#define GetLZMAState(tif) ((LZMAState *)(tif)->tif_data)
64
0
#define LZMADecoderState(tif) GetLZMAState(tif)
65
0
#define LZMAEncoderState(tif) GetLZMAState(tif)
66
67
static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
68
static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
69
70
static const char *LZMAStrerror(lzma_ret ret)
71
0
{
72
0
    switch (ret)
73
0
    {
74
0
        case LZMA_OK:
75
0
            return "operation completed successfully";
76
0
        case LZMA_STREAM_END:
77
0
            return "end of stream was reached";
78
0
        case LZMA_NO_CHECK:
79
0
            return "input stream has no integrity check";
80
0
        case LZMA_UNSUPPORTED_CHECK:
81
0
            return "cannot calculate the integrity check";
82
0
        case LZMA_GET_CHECK:
83
0
            return "integrity check type is now available";
84
0
        case LZMA_MEM_ERROR:
85
0
            return "cannot allocate memory";
86
0
        case LZMA_MEMLIMIT_ERROR:
87
0
            return "memory usage limit was reached";
88
0
        case LZMA_FORMAT_ERROR:
89
0
            return "file format not recognized";
90
0
        case LZMA_OPTIONS_ERROR:
91
0
            return "invalid or unsupported options";
92
0
        case LZMA_DATA_ERROR:
93
0
            return "data is corrupt";
94
0
        case LZMA_BUF_ERROR:
95
0
            return "no progress is possible (stream is truncated or corrupt)";
96
0
        case LZMA_PROG_ERROR:
97
0
            return "programming error";
98
#if LZMA_VERSION >= 50040000 /* 5.4.0 */
99
        case LZMA_SEEK_NEEDED:
100
        case LZMA_RET_INTERNAL1:
101
        case LZMA_RET_INTERNAL2:
102
        case LZMA_RET_INTERNAL3:
103
        case LZMA_RET_INTERNAL4:
104
        case LZMA_RET_INTERNAL5:
105
        case LZMA_RET_INTERNAL6:
106
        case LZMA_RET_INTERNAL7:
107
        case LZMA_RET_INTERNAL8:
108
#endif
109
0
        default:
110
0
            return "unidentified liblzma error";
111
0
    }
112
0
}
113
114
static int LZMAFixupTags(TIFF *tif)
115
0
{
116
0
    (void)tif;
117
0
    return 1;
118
0
}
119
120
static int LZMASetupDecode(TIFF *tif)
121
0
{
122
0
    LZMAState *sp = LZMADecoderState(tif);
123
124
0
    assert(sp != NULL);
125
126
    /* if we were last encoding, terminate this mode */
127
0
    if (sp->state & LSTATE_INIT_ENCODE)
128
0
    {
129
0
        lzma_end(&sp->stream);
130
0
        sp->state = 0;
131
0
    }
132
133
0
    sp->state |= LSTATE_INIT_DECODE;
134
0
    return 1;
135
0
}
136
137
/*
138
 * Setup state for decoding a strip.
139
 */
140
static int LZMAPreDecode(TIFF *tif, uint16_t s)
141
0
{
142
0
    static const char module[] = "LZMAPreDecode";
143
0
    LZMAState *sp = LZMADecoderState(tif);
144
0
    lzma_ret ret;
145
146
0
    (void)s;
147
0
    assert(sp != NULL);
148
149
0
    if ((sp->state & LSTATE_INIT_DECODE) == 0)
150
0
        tif->tif_setupdecode(tif);
151
152
0
    sp->stream.next_in = tif->tif_rawdata;
153
0
    sp->stream.avail_in = (size_t)tif->tif_rawcc;
154
0
    if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
155
0
    {
156
0
        TIFFErrorExtR(tif, module,
157
0
                      "Liblzma cannot deal with buffers this size");
158
0
        return 0;
159
0
    }
160
161
    /*
162
     * Disable memory limit when decoding. UINT64_MAX is a flag to disable
163
     * the limit, we are passing (uint64_t)-1 which should be the same.
164
     */
165
0
    ret = lzma_stream_decoder(&sp->stream, (uint64_t)-1, 0);
166
0
    if (ret != LZMA_OK)
167
0
    {
168
0
        TIFFErrorExtR(tif, module, "Error initializing the stream decoder, %s",
169
0
                      LZMAStrerror(ret));
170
0
        return 0;
171
0
    }
172
173
0
    sp->read_error = 0;
174
175
0
    return 1;
176
0
}
177
178
static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
179
0
{
180
0
    static const char module[] = "LZMADecode";
181
0
    LZMAState *sp = LZMADecoderState(tif);
182
183
0
    (void)s;
184
0
    assert(sp != NULL);
185
0
    assert(sp->state == LSTATE_INIT_DECODE);
186
187
0
    if (sp->read_error)
188
0
    {
189
0
        memset(op, 0, (size_t)occ);
190
0
        TIFFErrorExtR(tif, module,
191
0
                      "LZMADecode: Scanline %" PRIu32 " cannot be read due to "
192
0
                      "previous error",
193
0
                      tif->tif_row);
194
0
        return 0;
195
0
    }
196
197
0
    sp->stream.next_in = tif->tif_rawcp;
198
0
    sp->stream.avail_in = (size_t)tif->tif_rawcc;
199
200
0
    sp->stream.next_out = op;
201
0
    sp->stream.avail_out = (size_t)occ;
202
0
    if ((tmsize_t)sp->stream.avail_out != occ)
203
0
    {
204
        // read_error not set here as this is a usage issue that can be
205
        // recovered in a following call.
206
0
        memset(op, 0, (size_t)occ);
207
0
        TIFFErrorExtR(tif, module,
208
0
                      "Liblzma cannot deal with buffers this size");
209
0
        return 0;
210
0
    }
211
212
0
    do
213
0
    {
214
        /*
215
         * Save the current stream state to properly recover from the
216
         * decoding errors later.
217
         */
218
0
        const uint8_t *next_in = sp->stream.next_in;
219
0
        size_t avail_in = sp->stream.avail_in;
220
221
0
        lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN);
222
0
        if (ret == LZMA_STREAM_END)
223
0
            break;
224
0
        if (ret == LZMA_MEMLIMIT_ERROR)
225
0
        {
226
0
            lzma_ret r =
227
0
                lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0);
228
0
            if (r != LZMA_OK)
229
0
            {
230
0
                sp->read_error = 1;
231
0
                memset(op, 0, (size_t)occ);
232
0
                TIFFErrorExtR(tif, module,
233
0
                              "Error initializing the stream decoder, %s",
234
0
                              LZMAStrerror(r));
235
0
                break;
236
0
            }
237
0
            sp->stream.next_in = next_in;
238
0
            sp->stream.avail_in = avail_in;
239
0
            continue;
240
0
        }
241
0
        if (ret != LZMA_OK)
242
0
        {
243
0
            TIFFErrorExtR(tif, module,
244
0
                          "Decoding error at scanline %" PRIu32 ", %s",
245
0
                          tif->tif_row, LZMAStrerror(ret));
246
0
            break;
247
0
        }
248
0
    } while (sp->stream.avail_out > 0);
249
0
    if (sp->stream.avail_out != 0)
250
0
    {
251
0
        sp->read_error = 1;
252
0
        memset(sp->stream.next_out, 0, sp->stream.avail_out);
253
0
        TIFFErrorExtR(tif, module,
254
0
                      "Not enough data at scanline %" PRIu32
255
0
                      " (short %" TIFF_SIZE_FORMAT " bytes)",
256
0
                      tif->tif_row, sp->stream.avail_out);
257
0
        return 0;
258
0
    }
259
260
0
    tif->tif_rawcp = (uint8_t *)sp->stream.next_in; /* cast away const */
261
0
    tif->tif_rawcc = sp->stream.avail_in;
262
263
0
    return 1;
264
0
}
265
266
static int LZMASetupEncode(TIFF *tif)
267
0
{
268
0
    LZMAState *sp = LZMAEncoderState(tif);
269
270
0
    assert(sp != NULL);
271
0
    if (sp->state & LSTATE_INIT_DECODE)
272
0
    {
273
0
        lzma_end(&sp->stream);
274
0
        sp->state = 0;
275
0
    }
276
277
0
    sp->state |= LSTATE_INIT_ENCODE;
278
0
    return 1;
279
0
}
280
281
/*
282
 * Reset encoding state at the start of a strip.
283
 */
284
static int LZMAPreEncode(TIFF *tif, uint16_t s)
285
0
{
286
0
    static const char module[] = "LZMAPreEncode";
287
0
    LZMAState *sp = LZMAEncoderState(tif);
288
0
    lzma_ret ret;
289
290
0
    (void)s;
291
0
    assert(sp != NULL);
292
0
    if (sp->state != LSTATE_INIT_ENCODE)
293
0
        tif->tif_setupencode(tif);
294
295
0
    sp->stream.next_out = tif->tif_rawdata;
296
0
    sp->stream.avail_out = (size_t)tif->tif_rawdatasize;
297
0
    if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
298
0
    {
299
0
        TIFFErrorExtR(tif, module,
300
0
                      "Liblzma cannot deal with buffers this size");
301
0
        return 0;
302
0
    }
303
0
    ret = lzma_stream_encoder(&sp->stream, sp->filters, sp->check);
304
0
    if (ret != LZMA_OK)
305
0
    {
306
0
        TIFFErrorExtR(tif, module, "Error in lzma_stream_encoder(): %s",
307
0
                      LZMAStrerror(ret));
308
0
        return 0;
309
0
    }
310
0
    return 1;
311
0
}
312
313
/*
314
 * Encode a chunk of pixels.
315
 */
316
static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
317
0
{
318
0
    static const char module[] = "LZMAEncode";
319
0
    LZMAState *sp = LZMAEncoderState(tif);
320
321
0
    assert(sp != NULL);
322
0
    assert(sp->state == LSTATE_INIT_ENCODE);
323
324
0
    (void)s;
325
0
    sp->stream.next_in = bp;
326
0
    sp->stream.avail_in = (size_t)cc;
327
0
    if ((tmsize_t)sp->stream.avail_in != cc)
328
0
    {
329
0
        TIFFErrorExtR(tif, module,
330
0
                      "Liblzma cannot deal with buffers this size");
331
0
        return 0;
332
0
    }
333
0
    do
334
0
    {
335
0
        lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN);
336
0
        if (ret != LZMA_OK)
337
0
        {
338
0
            TIFFErrorExtR(tif, module,
339
0
                          "Encoding error at scanline %" PRIu32 ", %s",
340
0
                          tif->tif_row, LZMAStrerror(ret));
341
0
            return 0;
342
0
        }
343
0
        if (sp->stream.avail_out == 0)
344
0
        {
345
0
            tif->tif_rawcc = tif->tif_rawdatasize;
346
0
            if (!TIFFFlushData1(tif))
347
0
                return 0;
348
0
            sp->stream.next_out = tif->tif_rawdata;
349
0
            sp->stream.avail_out =
350
0
                (size_t)
351
0
                    tif->tif_rawdatasize; /* this is a safe typecast, as check
352
                                             is made already in LZMAPreEncode */
353
0
        }
354
0
    } while (sp->stream.avail_in > 0);
355
0
    return 1;
356
0
}
357
358
/*
359
 * Finish off an encoded strip by flushing the last
360
 * string and tacking on an End Of Information code.
361
 */
362
static int LZMAPostEncode(TIFF *tif)
363
0
{
364
0
    static const char module[] = "LZMAPostEncode";
365
0
    LZMAState *sp = LZMAEncoderState(tif);
366
0
    lzma_ret ret;
367
368
0
    sp->stream.avail_in = 0;
369
0
    do
370
0
    {
371
0
        ret = lzma_code(&sp->stream, LZMA_FINISH);
372
0
        switch (ret)
373
0
        {
374
0
            case LZMA_STREAM_END:
375
0
            case LZMA_OK:
376
0
                if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
377
0
                {
378
0
                    tif->tif_rawcc =
379
0
                        tif->tif_rawdatasize - sp->stream.avail_out;
380
0
                    if (!TIFFFlushData1(tif))
381
0
                        return 0;
382
0
                    sp->stream.next_out = tif->tif_rawdata;
383
0
                    sp->stream.avail_out =
384
0
                        (size_t)
385
0
                            tif->tif_rawdatasize; /* this is a safe typecast, as
386
                                                     check is made already in
387
                                                     ZIPPreEncode */
388
0
                }
389
0
                break;
390
0
            case LZMA_NO_CHECK:
391
0
            case LZMA_UNSUPPORTED_CHECK:
392
0
            case LZMA_GET_CHECK:
393
0
            case LZMA_MEM_ERROR:
394
0
            case LZMA_MEMLIMIT_ERROR:
395
0
            case LZMA_FORMAT_ERROR:
396
0
            case LZMA_OPTIONS_ERROR:
397
0
            case LZMA_DATA_ERROR:
398
0
            case LZMA_BUF_ERROR:
399
0
            case LZMA_PROG_ERROR:
400
#if LZMA_VERSION >= 50040000 /* 5.4.0 */
401
            case LZMA_SEEK_NEEDED:
402
            case LZMA_RET_INTERNAL1:
403
            case LZMA_RET_INTERNAL2:
404
            case LZMA_RET_INTERNAL3:
405
            case LZMA_RET_INTERNAL4:
406
            case LZMA_RET_INTERNAL5:
407
            case LZMA_RET_INTERNAL6:
408
            case LZMA_RET_INTERNAL7:
409
            case LZMA_RET_INTERNAL8:
410
#endif
411
0
            default:
412
0
                TIFFErrorExtR(tif, module, "Liblzma error: %s",
413
0
                              LZMAStrerror(ret));
414
0
                return 0;
415
0
        }
416
0
    } while (ret != LZMA_STREAM_END);
417
0
    return 1;
418
0
}
419
420
static void LZMACleanup(TIFF *tif)
421
0
{
422
0
    LZMAState *sp = GetLZMAState(tif);
423
424
0
    assert(sp != 0);
425
426
0
    (void)TIFFPredictorCleanup(tif);
427
428
0
    tif->tif_tagmethods.vgetfield = sp->vgetparent;
429
0
    tif->tif_tagmethods.vsetfield = sp->vsetparent;
430
431
0
    if (sp->state)
432
0
    {
433
0
        lzma_end(&sp->stream);
434
0
        sp->state = 0;
435
0
    }
436
0
    _TIFFfreeExt(tif, sp);
437
0
    tif->tif_data = NULL;
438
439
0
    _TIFFSetDefaultCompressionState(tif);
440
0
}
441
442
static int LZMAVSetField(TIFF *tif, uint32_t tag, va_list ap)
443
0
{
444
0
    static const char module[] = "LZMAVSetField";
445
0
    LZMAState *sp = GetLZMAState(tif);
446
447
0
    switch (tag)
448
0
    {
449
0
        case TIFFTAG_LZMAPRESET:
450
0
            sp->preset = (int)va_arg(ap, int);
451
0
            lzma_lzma_preset(&sp->opt_lzma, sp->preset);
452
0
            if (sp->state & LSTATE_INIT_ENCODE)
453
0
            {
454
0
                lzma_ret ret =
455
0
                    lzma_stream_encoder(&sp->stream, sp->filters, sp->check);
456
0
                if (ret != LZMA_OK)
457
0
                {
458
0
                    TIFFErrorExtR(tif, module, "Liblzma error: %s",
459
0
                                  LZMAStrerror(ret));
460
0
                }
461
0
            }
462
0
            return 1;
463
0
        default:
464
0
            return (*sp->vsetparent)(tif, tag, ap);
465
0
    }
466
    /*NOTREACHED*/
467
0
}
468
469
static int LZMAVGetField(TIFF *tif, uint32_t tag, va_list ap)
470
0
{
471
0
    LZMAState *sp = GetLZMAState(tif);
472
473
0
    switch (tag)
474
0
    {
475
0
        case TIFFTAG_LZMAPRESET:
476
0
            *va_arg(ap, int *) = sp->preset;
477
0
            break;
478
0
        default:
479
0
            return (*sp->vgetparent)(tif, tag, ap);
480
0
    }
481
0
    return 1;
482
0
}
483
484
static const TIFFField lzmaFields[] = {
485
    {TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE,
486
     FALSE, "LZMA2 Compression Preset", NULL},
487
};
488
489
int TIFFInitLZMA(TIFF *tif, int scheme)
490
0
{
491
0
    static const char module[] = "TIFFInitLZMA";
492
0
    LZMAState *sp;
493
0
    lzma_stream tmp_stream = LZMA_STREAM_INIT;
494
495
0
    (void)scheme;
496
0
    assert(scheme == COMPRESSION_LZMA);
497
498
    /*
499
     * Merge codec-specific tag information.
500
     */
501
0
    if (!_TIFFMergeFields(tif, lzmaFields, TIFFArrayCount(lzmaFields)))
502
0
    {
503
0
        TIFFErrorExtR(tif, module, "Merging LZMA2 codec-specific tags failed");
504
0
        return 0;
505
0
    }
506
507
    /*
508
     * Allocate state block so tag methods have storage to record values.
509
     */
510
0
    tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZMAState));
511
0
    if (tif->tif_data == NULL)
512
0
        goto bad;
513
0
    sp = GetLZMAState(tif);
514
0
    memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream));
515
516
    /*
517
     * Override parent get/set field methods.
518
     */
519
0
    sp->vgetparent = tif->tif_tagmethods.vgetfield;
520
0
    tif->tif_tagmethods.vgetfield = LZMAVGetField; /* hook for codec tags */
521
0
    sp->vsetparent = tif->tif_tagmethods.vsetfield;
522
0
    tif->tif_tagmethods.vsetfield = LZMAVSetField; /* hook for codec tags */
523
524
    /* Default values for codec-specific fields */
525
0
    sp->preset = LZMA_PRESET_DEFAULT; /* default comp. level */
526
0
    sp->check = LZMA_CHECK_NONE;
527
0
    sp->state = 0;
528
529
    /* Data filters. So far we are using delta and LZMA2 filters only. */
530
0
    sp->opt_delta.type = LZMA_DELTA_TYPE_BYTE;
531
    /*
532
     * The sample size in bytes seems to be reasonable distance for delta
533
     * filter.
534
     */
535
0
    sp->opt_delta.dist = (tif->tif_dir.td_bitspersample % 8)
536
0
                             ? 1
537
0
                             : tif->tif_dir.td_bitspersample / 8;
538
0
    sp->filters[0].id = LZMA_FILTER_DELTA;
539
0
    sp->filters[0].options = &sp->opt_delta;
540
541
0
    lzma_lzma_preset(&sp->opt_lzma, sp->preset);
542
0
    sp->filters[1].id = LZMA_FILTER_LZMA2;
543
0
    sp->filters[1].options = &sp->opt_lzma;
544
545
0
    sp->filters[2].id = LZMA_VLI_UNKNOWN;
546
0
    sp->filters[2].options = NULL;
547
548
    /*
549
     * Install codec methods.
550
     */
551
0
    tif->tif_fixuptags = LZMAFixupTags;
552
0
    tif->tif_setupdecode = LZMASetupDecode;
553
0
    tif->tif_predecode = LZMAPreDecode;
554
0
    tif->tif_decoderow = LZMADecode;
555
0
    tif->tif_decodestrip = LZMADecode;
556
0
    tif->tif_decodetile = LZMADecode;
557
0
    tif->tif_setupencode = LZMASetupEncode;
558
0
    tif->tif_preencode = LZMAPreEncode;
559
0
    tif->tif_postencode = LZMAPostEncode;
560
0
    tif->tif_encoderow = LZMAEncode;
561
0
    tif->tif_encodestrip = LZMAEncode;
562
0
    tif->tif_encodetile = LZMAEncode;
563
0
    tif->tif_cleanup = LZMACleanup;
564
    /*
565
     * Setup predictor setup.
566
     */
567
0
    (void)TIFFPredictorInit(tif);
568
0
    return 1;
569
0
bad:
570
0
    TIFFErrorExtR(tif, module, "No space for LZMA2 state block");
571
0
    return 0;
572
0
}
573
#endif /* LZMA_SUPPORT */