LCOV - code coverage report
Current view: top level - frmts/gtiff/libtiff - tif_lzma.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 153 236 64.8 %
Date: 2024-05-04 12:52:34 Functions: 12 13 92.3 %

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

Generated by: LCOV version 1.14