Coverage Report

Created: 2025-06-13 06:18

/src/gdal/frmts/gtiff/libtiff/tif_lzma.c
Line
Count
Source (jump to first uncovered line)
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
0
        default:
99
0
            return "unidentified liblzma error";
100
0
    }
101
0
}
102
103
static int LZMAFixupTags(TIFF *tif)
104
0
{
105
0
    (void)tif;
106
0
    return 1;
107
0
}
108
109
static int LZMASetupDecode(TIFF *tif)
110
0
{
111
0
    LZMAState *sp = LZMADecoderState(tif);
112
113
0
    assert(sp != NULL);
114
115
    /* if we were last encoding, terminate this mode */
116
0
    if (sp->state & LSTATE_INIT_ENCODE)
117
0
    {
118
0
        lzma_end(&sp->stream);
119
0
        sp->state = 0;
120
0
    }
121
122
0
    sp->state |= LSTATE_INIT_DECODE;
123
0
    return 1;
124
0
}
125
126
/*
127
 * Setup state for decoding a strip.
128
 */
129
static int LZMAPreDecode(TIFF *tif, uint16_t s)
130
0
{
131
0
    static const char module[] = "LZMAPreDecode";
132
0
    LZMAState *sp = LZMADecoderState(tif);
133
0
    lzma_ret ret;
134
135
0
    (void)s;
136
0
    assert(sp != NULL);
137
138
0
    if ((sp->state & LSTATE_INIT_DECODE) == 0)
139
0
        tif->tif_setupdecode(tif);
140
141
0
    sp->stream.next_in = tif->tif_rawdata;
142
0
    sp->stream.avail_in = (size_t)tif->tif_rawcc;
143
0
    if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
144
0
    {
145
0
        TIFFErrorExtR(tif, module,
146
0
                      "Liblzma cannot deal with buffers this size");
147
0
        return 0;
148
0
    }
149
150
    /*
151
     * Disable memory limit when decoding. UINT64_MAX is a flag to disable
152
     * the limit, we are passing (uint64_t)-1 which should be the same.
153
     */
154
0
    ret = lzma_stream_decoder(&sp->stream, (uint64_t)-1, 0);
155
0
    if (ret != LZMA_OK)
156
0
    {
157
0
        TIFFErrorExtR(tif, module, "Error initializing the stream decoder, %s",
158
0
                      LZMAStrerror(ret));
159
0
        return 0;
160
0
    }
161
162
0
    sp->read_error = 0;
163
164
0
    return 1;
165
0
}
166
167
static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
168
0
{
169
0
    static const char module[] = "LZMADecode";
170
0
    LZMAState *sp = LZMADecoderState(tif);
171
172
0
    (void)s;
173
0
    assert(sp != NULL);
174
0
    assert(sp->state == LSTATE_INIT_DECODE);
175
176
0
    if (sp->read_error)
177
0
    {
178
0
        memset(op, 0, (size_t)occ);
179
0
        TIFFErrorExtR(tif, module,
180
0
                      "LZMADecode: Scanline %" PRIu32 " cannot be read due to "
181
0
                      "previous error",
182
0
                      tif->tif_row);
183
0
        return 0;
184
0
    }
185
186
0
    sp->stream.next_in = tif->tif_rawcp;
187
0
    sp->stream.avail_in = (size_t)tif->tif_rawcc;
188
189
0
    sp->stream.next_out = op;
190
0
    sp->stream.avail_out = (size_t)occ;
191
0
    if ((tmsize_t)sp->stream.avail_out != occ)
192
0
    {
193
        // read_error not set here as this is a usage issue that can be
194
        // recovered in a following call.
195
0
        memset(op, 0, (size_t)occ);
196
0
        TIFFErrorExtR(tif, module,
197
0
                      "Liblzma cannot deal with buffers this size");
198
0
        return 0;
199
0
    }
200
201
0
    do
202
0
    {
203
        /*
204
         * Save the current stream state to properly recover from the
205
         * decoding errors later.
206
         */
207
0
        const uint8_t *next_in = sp->stream.next_in;
208
0
        size_t avail_in = sp->stream.avail_in;
209
210
0
        lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN);
211
0
        if (ret == LZMA_STREAM_END)
212
0
            break;
213
0
        if (ret == LZMA_MEMLIMIT_ERROR)
214
0
        {
215
0
            lzma_ret r =
216
0
                lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0);
217
0
            if (r != LZMA_OK)
218
0
            {
219
0
                sp->read_error = 1;
220
0
                memset(op, 0, (size_t)occ);
221
0
                TIFFErrorExtR(tif, module,
222
0
                              "Error initializing the stream decoder, %s",
223
0
                              LZMAStrerror(r));
224
0
                break;
225
0
            }
226
0
            sp->stream.next_in = next_in;
227
0
            sp->stream.avail_in = avail_in;
228
0
            continue;
229
0
        }
230
0
        if (ret != LZMA_OK)
231
0
        {
232
0
            TIFFErrorExtR(tif, module,
233
0
                          "Decoding error at scanline %" PRIu32 ", %s",
234
0
                          tif->tif_row, LZMAStrerror(ret));
235
0
            break;
236
0
        }
237
0
    } while (sp->stream.avail_out > 0);
238
0
    if (sp->stream.avail_out != 0)
239
0
    {
240
0
        sp->read_error = 1;
241
0
        memset(sp->stream.next_out, 0, sp->stream.avail_out);
242
0
        TIFFErrorExtR(tif, module,
243
0
                      "Not enough data at scanline %" PRIu32
244
0
                      " (short %" TIFF_SIZE_FORMAT " bytes)",
245
0
                      tif->tif_row, sp->stream.avail_out);
246
0
        return 0;
247
0
    }
248
249
0
    tif->tif_rawcp = (uint8_t *)sp->stream.next_in; /* cast away const */
250
0
    tif->tif_rawcc = sp->stream.avail_in;
251
252
0
    return 1;
253
0
}
254
255
static int LZMASetupEncode(TIFF *tif)
256
0
{
257
0
    LZMAState *sp = LZMAEncoderState(tif);
258
259
0
    assert(sp != NULL);
260
0
    if (sp->state & LSTATE_INIT_DECODE)
261
0
    {
262
0
        lzma_end(&sp->stream);
263
0
        sp->state = 0;
264
0
    }
265
266
0
    sp->state |= LSTATE_INIT_ENCODE;
267
0
    return 1;
268
0
}
269
270
/*
271
 * Reset encoding state at the start of a strip.
272
 */
273
static int LZMAPreEncode(TIFF *tif, uint16_t s)
274
0
{
275
0
    static const char module[] = "LZMAPreEncode";
276
0
    LZMAState *sp = LZMAEncoderState(tif);
277
0
    lzma_ret ret;
278
279
0
    (void)s;
280
0
    assert(sp != NULL);
281
0
    if (sp->state != LSTATE_INIT_ENCODE)
282
0
        tif->tif_setupencode(tif);
283
284
0
    sp->stream.next_out = tif->tif_rawdata;
285
0
    sp->stream.avail_out = (size_t)tif->tif_rawdatasize;
286
0
    if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
287
0
    {
288
0
        TIFFErrorExtR(tif, module,
289
0
                      "Liblzma cannot deal with buffers this size");
290
0
        return 0;
291
0
    }
292
0
    ret = lzma_stream_encoder(&sp->stream, sp->filters, sp->check);
293
0
    if (ret != LZMA_OK)
294
0
    {
295
0
        TIFFErrorExtR(tif, module, "Error in lzma_stream_encoder(): %s",
296
0
                      LZMAStrerror(ret));
297
0
        return 0;
298
0
    }
299
0
    return 1;
300
0
}
301
302
/*
303
 * Encode a chunk of pixels.
304
 */
305
static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
306
0
{
307
0
    static const char module[] = "LZMAEncode";
308
0
    LZMAState *sp = LZMAEncoderState(tif);
309
310
0
    assert(sp != NULL);
311
0
    assert(sp->state == LSTATE_INIT_ENCODE);
312
313
0
    (void)s;
314
0
    sp->stream.next_in = bp;
315
0
    sp->stream.avail_in = (size_t)cc;
316
0
    if ((tmsize_t)sp->stream.avail_in != cc)
317
0
    {
318
0
        TIFFErrorExtR(tif, module,
319
0
                      "Liblzma cannot deal with buffers this size");
320
0
        return 0;
321
0
    }
322
0
    do
323
0
    {
324
0
        lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN);
325
0
        if (ret != LZMA_OK)
326
0
        {
327
0
            TIFFErrorExtR(tif, module,
328
0
                          "Encoding error at scanline %" PRIu32 ", %s",
329
0
                          tif->tif_row, LZMAStrerror(ret));
330
0
            return 0;
331
0
        }
332
0
        if (sp->stream.avail_out == 0)
333
0
        {
334
0
            tif->tif_rawcc = tif->tif_rawdatasize;
335
0
            if (!TIFFFlushData1(tif))
336
0
                return 0;
337
0
            sp->stream.next_out = tif->tif_rawdata;
338
0
            sp->stream.avail_out =
339
0
                (size_t)
340
0
                    tif->tif_rawdatasize; /* this is a safe typecast, as check
341
                                             is made already in LZMAPreEncode */
342
0
        }
343
0
    } while (sp->stream.avail_in > 0);
344
0
    return 1;
345
0
}
346
347
/*
348
 * Finish off an encoded strip by flushing the last
349
 * string and tacking on an End Of Information code.
350
 */
351
static int LZMAPostEncode(TIFF *tif)
352
0
{
353
0
    static const char module[] = "LZMAPostEncode";
354
0
    LZMAState *sp = LZMAEncoderState(tif);
355
0
    lzma_ret ret;
356
357
0
    sp->stream.avail_in = 0;
358
0
    do
359
0
    {
360
0
        ret = lzma_code(&sp->stream, LZMA_FINISH);
361
0
        switch (ret)
362
0
        {
363
0
            case LZMA_STREAM_END:
364
0
            case LZMA_OK:
365
0
                if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
366
0
                {
367
0
                    tif->tif_rawcc =
368
0
                        tif->tif_rawdatasize - sp->stream.avail_out;
369
0
                    if (!TIFFFlushData1(tif))
370
0
                        return 0;
371
0
                    sp->stream.next_out = tif->tif_rawdata;
372
0
                    sp->stream.avail_out =
373
0
                        (size_t)
374
0
                            tif->tif_rawdatasize; /* this is a safe typecast, as
375
                                                     check is made already in
376
                                                     ZIPPreEncode */
377
0
                }
378
0
                break;
379
0
            default:
380
0
                TIFFErrorExtR(tif, module, "Liblzma error: %s",
381
0
                              LZMAStrerror(ret));
382
0
                return 0;
383
0
        }
384
0
    } while (ret != LZMA_STREAM_END);
385
0
    return 1;
386
0
}
387
388
static void LZMACleanup(TIFF *tif)
389
0
{
390
0
    LZMAState *sp = GetLZMAState(tif);
391
392
0
    assert(sp != 0);
393
394
0
    (void)TIFFPredictorCleanup(tif);
395
396
0
    tif->tif_tagmethods.vgetfield = sp->vgetparent;
397
0
    tif->tif_tagmethods.vsetfield = sp->vsetparent;
398
399
0
    if (sp->state)
400
0
    {
401
0
        lzma_end(&sp->stream);
402
0
        sp->state = 0;
403
0
    }
404
0
    _TIFFfreeExt(tif, sp);
405
0
    tif->tif_data = NULL;
406
407
0
    _TIFFSetDefaultCompressionState(tif);
408
0
}
409
410
static int LZMAVSetField(TIFF *tif, uint32_t tag, va_list ap)
411
0
{
412
0
    static const char module[] = "LZMAVSetField";
413
0
    LZMAState *sp = GetLZMAState(tif);
414
415
0
    switch (tag)
416
0
    {
417
0
        case TIFFTAG_LZMAPRESET:
418
0
            sp->preset = (int)va_arg(ap, int);
419
0
            lzma_lzma_preset(&sp->opt_lzma, sp->preset);
420
0
            if (sp->state & LSTATE_INIT_ENCODE)
421
0
            {
422
0
                lzma_ret ret =
423
0
                    lzma_stream_encoder(&sp->stream, sp->filters, sp->check);
424
0
                if (ret != LZMA_OK)
425
0
                {
426
0
                    TIFFErrorExtR(tif, module, "Liblzma error: %s",
427
0
                                  LZMAStrerror(ret));
428
0
                }
429
0
            }
430
0
            return 1;
431
0
        default:
432
0
            return (*sp->vsetparent)(tif, tag, ap);
433
0
    }
434
    /*NOTREACHED*/
435
0
}
436
437
static int LZMAVGetField(TIFF *tif, uint32_t tag, va_list ap)
438
0
{
439
0
    LZMAState *sp = GetLZMAState(tif);
440
441
0
    switch (tag)
442
0
    {
443
0
        case TIFFTAG_LZMAPRESET:
444
0
            *va_arg(ap, int *) = sp->preset;
445
0
            break;
446
0
        default:
447
0
            return (*sp->vgetparent)(tif, tag, ap);
448
0
    }
449
0
    return 1;
450
0
}
451
452
static const TIFFField lzmaFields[] = {
453
    {TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE,
454
     FALSE, "LZMA2 Compression Preset", NULL},
455
};
456
457
int TIFFInitLZMA(TIFF *tif, int scheme)
458
0
{
459
0
    static const char module[] = "TIFFInitLZMA";
460
0
    LZMAState *sp;
461
0
    lzma_stream tmp_stream = LZMA_STREAM_INIT;
462
463
0
    (void)scheme;
464
0
    assert(scheme == COMPRESSION_LZMA);
465
466
    /*
467
     * Merge codec-specific tag information.
468
     */
469
0
    if (!_TIFFMergeFields(tif, lzmaFields, TIFFArrayCount(lzmaFields)))
470
0
    {
471
0
        TIFFErrorExtR(tif, module, "Merging LZMA2 codec-specific tags failed");
472
0
        return 0;
473
0
    }
474
475
    /*
476
     * Allocate state block so tag methods have storage to record values.
477
     */
478
0
    tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZMAState));
479
0
    if (tif->tif_data == NULL)
480
0
        goto bad;
481
0
    sp = GetLZMAState(tif);
482
0
    memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream));
483
484
    /*
485
     * Override parent get/set field methods.
486
     */
487
0
    sp->vgetparent = tif->tif_tagmethods.vgetfield;
488
0
    tif->tif_tagmethods.vgetfield = LZMAVGetField; /* hook for codec tags */
489
0
    sp->vsetparent = tif->tif_tagmethods.vsetfield;
490
0
    tif->tif_tagmethods.vsetfield = LZMAVSetField; /* hook for codec tags */
491
492
    /* Default values for codec-specific fields */
493
0
    sp->preset = LZMA_PRESET_DEFAULT; /* default comp. level */
494
0
    sp->check = LZMA_CHECK_NONE;
495
0
    sp->state = 0;
496
497
    /* Data filters. So far we are using delta and LZMA2 filters only. */
498
0
    sp->opt_delta.type = LZMA_DELTA_TYPE_BYTE;
499
    /*
500
     * The sample size in bytes seems to be reasonable distance for delta
501
     * filter.
502
     */
503
0
    sp->opt_delta.dist = (tif->tif_dir.td_bitspersample % 8)
504
0
                             ? 1
505
0
                             : tif->tif_dir.td_bitspersample / 8;
506
0
    sp->filters[0].id = LZMA_FILTER_DELTA;
507
0
    sp->filters[0].options = &sp->opt_delta;
508
509
0
    lzma_lzma_preset(&sp->opt_lzma, sp->preset);
510
0
    sp->filters[1].id = LZMA_FILTER_LZMA2;
511
0
    sp->filters[1].options = &sp->opt_lzma;
512
513
0
    sp->filters[2].id = LZMA_VLI_UNKNOWN;
514
0
    sp->filters[2].options = NULL;
515
516
    /*
517
     * Install codec methods.
518
     */
519
0
    tif->tif_fixuptags = LZMAFixupTags;
520
0
    tif->tif_setupdecode = LZMASetupDecode;
521
0
    tif->tif_predecode = LZMAPreDecode;
522
0
    tif->tif_decoderow = LZMADecode;
523
0
    tif->tif_decodestrip = LZMADecode;
524
0
    tif->tif_decodetile = LZMADecode;
525
0
    tif->tif_setupencode = LZMASetupEncode;
526
0
    tif->tif_preencode = LZMAPreEncode;
527
0
    tif->tif_postencode = LZMAPostEncode;
528
0
    tif->tif_encoderow = LZMAEncode;
529
0
    tif->tif_encodestrip = LZMAEncode;
530
0
    tif->tif_encodetile = LZMAEncode;
531
0
    tif->tif_cleanup = LZMACleanup;
532
    /*
533
     * Setup predictor setup.
534
     */
535
0
    (void)TIFFPredictorInit(tif);
536
0
    return 1;
537
0
bad:
538
0
    TIFFErrorExtR(tif, module, "No space for LZMA2 state block");
539
0
    return 0;
540
0
}
541
#endif /* LZMA_SUPPORT */