LCOV - code coverage report
Current view: top level - frmts/gtiff/libtiff - tif_zstd.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 147 184 79.9 %
Date: 2024-05-03 15:49:35 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017, Planet Labs
       3             :  * Author: <even.rouault at spatialys.com>
       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             :  * 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 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 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 ZSTD_SUPPORT
      27             : /*
      28             :  * TIFF Library.
      29             :  *
      30             :  * ZSTD Compression Support
      31             :  *
      32             :  */
      33             : 
      34             : #include "tif_predict.h"
      35             : #include "zstd.h"
      36             : 
      37             : #include <stdio.h>
      38             : 
      39             : /*
      40             :  * State block for each open TIFF file using ZSTD compression/decompression.
      41             :  */
      42             : typedef struct
      43             : {
      44             :     TIFFPredictorState predict;
      45             :     ZSTD_DStream *dstream;
      46             :     ZSTD_CStream *cstream;
      47             :     int compression_level; /* compression level */
      48             :     ZSTD_outBuffer out_buffer;
      49             :     int state; /* state flags */
      50             : #define LSTATE_INIT_DECODE 0x01
      51             : #define LSTATE_INIT_ENCODE 0x02
      52             : 
      53             :     TIFFVGetMethod vgetparent; /* super-class method */
      54             :     TIFFVSetMethod vsetparent; /* super-class method */
      55             : } ZSTDState;
      56             : 
      57             : #define GetZSTDState(tif) ((ZSTDState *)(tif)->tif_data)
      58             : #define ZSTDDecoderState(tif) GetZSTDState(tif)
      59             : #define ZSTDEncoderState(tif) GetZSTDState(tif)
      60             : 
      61             : static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
      62             : static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
      63             : 
      64         649 : static int ZSTDFixupTags(TIFF *tif)
      65             : {
      66             :     (void)tif;
      67         649 :     return 1;
      68             : }
      69             : 
      70         141 : static int ZSTDSetupDecode(TIFF *tif)
      71             : {
      72         141 :     ZSTDState *sp = ZSTDDecoderState(tif);
      73             : 
      74         141 :     assert(sp != NULL);
      75             : 
      76             :     /* if we were last encoding, terminate this mode */
      77         141 :     if (sp->state & LSTATE_INIT_ENCODE)
      78             :     {
      79          17 :         ZSTD_freeCStream(sp->cstream);
      80          17 :         sp->cstream = NULL;
      81          17 :         sp->state = 0;
      82             :     }
      83             : 
      84         141 :     sp->state |= LSTATE_INIT_DECODE;
      85         141 :     return 1;
      86             : }
      87             : 
      88             : /*
      89             :  * Setup state for decoding a strip.
      90             :  */
      91         398 : static int ZSTDPreDecode(TIFF *tif, uint16_t s)
      92             : {
      93             :     static const char module[] = "ZSTDPreDecode";
      94         398 :     ZSTDState *sp = ZSTDDecoderState(tif);
      95             :     size_t zstd_ret;
      96             : 
      97             :     (void)s;
      98         398 :     assert(sp != NULL);
      99             : 
     100         398 :     if ((sp->state & LSTATE_INIT_DECODE) == 0)
     101          17 :         tif->tif_setupdecode(tif);
     102             : 
     103         398 :     if (sp->dstream == NULL)
     104             :     {
     105         141 :         sp->dstream = ZSTD_createDStream();
     106         141 :         if (sp->dstream == NULL)
     107             :         {
     108           0 :             TIFFErrorExtR(tif, module, "Cannot allocate decompression stream");
     109           0 :             return 0;
     110             :         }
     111             :     }
     112             : 
     113         398 :     zstd_ret = ZSTD_initDStream(sp->dstream);
     114         398 :     if (ZSTD_isError(zstd_ret))
     115             :     {
     116           0 :         TIFFErrorExtR(tif, module, "Error in ZSTD_initDStream(): %s",
     117             :                       ZSTD_getErrorName(zstd_ret));
     118           0 :         return 0;
     119             :     }
     120             : 
     121         398 :     return 1;
     122             : }
     123             : 
     124         398 : static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
     125             : {
     126             :     static const char module[] = "ZSTDDecode";
     127         398 :     ZSTDState *sp = ZSTDDecoderState(tif);
     128             :     ZSTD_inBuffer in_buffer;
     129             :     ZSTD_outBuffer out_buffer;
     130             :     size_t zstd_ret;
     131             : 
     132             :     (void)s;
     133         398 :     assert(sp != NULL);
     134         398 :     assert(sp->state == LSTATE_INIT_DECODE);
     135             : 
     136         398 :     in_buffer.src = tif->tif_rawcp;
     137         398 :     in_buffer.size = (size_t)tif->tif_rawcc;
     138         398 :     in_buffer.pos = 0;
     139             : 
     140         398 :     out_buffer.dst = op;
     141         398 :     out_buffer.size = (size_t)occ;
     142         398 :     out_buffer.pos = 0;
     143             : 
     144             :     do
     145             :     {
     146         398 :         zstd_ret = ZSTD_decompressStream(sp->dstream, &out_buffer, &in_buffer);
     147         398 :         if (ZSTD_isError(zstd_ret))
     148             :         {
     149           2 :             TIFFErrorExtR(tif, module, "Error in ZSTD_decompressStream(): %s",
     150             :                           ZSTD_getErrorName(zstd_ret));
     151           2 :             return 0;
     152             :         }
     153         143 :     } while (zstd_ret != 0 && in_buffer.pos < in_buffer.size &&
     154         539 :              out_buffer.pos < out_buffer.size);
     155             : 
     156         396 :     if (out_buffer.pos < (size_t)occ)
     157             :     {
     158           0 :         TIFFErrorExtR(tif, module,
     159             :                       "Not enough data at scanline %lu (short %lu bytes)",
     160           0 :                       (unsigned long)tif->tif_row,
     161           0 :                       (unsigned long)((size_t)occ - out_buffer.pos));
     162           0 :         return 0;
     163             :     }
     164             : 
     165         396 :     tif->tif_rawcp += in_buffer.pos;
     166         396 :     tif->tif_rawcc -= in_buffer.pos;
     167             : 
     168         396 :     return 1;
     169             : }
     170             : 
     171         103 : static int ZSTDSetupEncode(TIFF *tif)
     172             : {
     173         103 :     ZSTDState *sp = ZSTDEncoderState(tif);
     174             : 
     175         103 :     assert(sp != NULL);
     176         103 :     if (sp->state & LSTATE_INIT_DECODE)
     177             :     {
     178           0 :         ZSTD_freeDStream(sp->dstream);
     179           0 :         sp->dstream = NULL;
     180           0 :         sp->state = 0;
     181             :     }
     182             : 
     183         103 :     sp->state |= LSTATE_INIT_ENCODE;
     184         103 :     return 1;
     185             : }
     186             : 
     187             : /*
     188             :  * Reset encoding state at the start of a strip.
     189             :  */
     190         242 : static int ZSTDPreEncode(TIFF *tif, uint16_t s)
     191             : {
     192             :     static const char module[] = "ZSTDPreEncode";
     193         242 :     ZSTDState *sp = ZSTDEncoderState(tif);
     194             :     size_t zstd_ret;
     195             : 
     196             :     (void)s;
     197         242 :     assert(sp != NULL);
     198         242 :     if (sp->state != LSTATE_INIT_ENCODE)
     199           0 :         tif->tif_setupencode(tif);
     200             : 
     201         242 :     if (sp->cstream == NULL)
     202             :     {
     203         103 :         sp->cstream = ZSTD_createCStream();
     204         103 :         if (sp->cstream == NULL)
     205             :         {
     206           0 :             TIFFErrorExtR(tif, module, "Cannot allocate compression stream");
     207           0 :             return 0;
     208             :         }
     209             :     }
     210             : 
     211         242 :     zstd_ret = ZSTD_initCStream(sp->cstream, sp->compression_level);
     212         242 :     if (ZSTD_isError(zstd_ret))
     213             :     {
     214           0 :         TIFFErrorExtR(tif, module, "Error in ZSTD_initCStream(): %s",
     215             :                       ZSTD_getErrorName(zstd_ret));
     216           0 :         return 0;
     217             :     }
     218             : 
     219         242 :     sp->out_buffer.dst = tif->tif_rawdata;
     220         242 :     sp->out_buffer.size = (size_t)tif->tif_rawdatasize;
     221         242 :     sp->out_buffer.pos = 0;
     222             : 
     223         242 :     return 1;
     224             : }
     225             : 
     226             : /*
     227             :  * Encode a chunk of pixels.
     228             :  */
     229         242 : static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
     230             : {
     231             :     static const char module[] = "ZSTDEncode";
     232         242 :     ZSTDState *sp = ZSTDEncoderState(tif);
     233             :     ZSTD_inBuffer in_buffer;
     234             :     size_t zstd_ret;
     235             : 
     236         242 :     assert(sp != NULL);
     237         242 :     assert(sp->state == LSTATE_INIT_ENCODE);
     238             : 
     239             :     (void)s;
     240             : 
     241         242 :     in_buffer.src = bp;
     242         242 :     in_buffer.size = (size_t)cc;
     243         242 :     in_buffer.pos = 0;
     244             : 
     245             :     do
     246             :     {
     247             :         zstd_ret =
     248         242 :             ZSTD_compressStream(sp->cstream, &sp->out_buffer, &in_buffer);
     249         242 :         if (ZSTD_isError(zstd_ret))
     250             :         {
     251           0 :             TIFFErrorExtR(tif, module, "Error in ZSTD_compressStream(): %s",
     252             :                           ZSTD_getErrorName(zstd_ret));
     253           0 :             return 0;
     254             :         }
     255         242 :         if (sp->out_buffer.pos == sp->out_buffer.size)
     256             :         {
     257           0 :             tif->tif_rawcc = tif->tif_rawdatasize;
     258           0 :             if (!TIFFFlushData1(tif))
     259           0 :                 return 0;
     260           0 :             sp->out_buffer.dst = tif->tif_rawcp;
     261           0 :             sp->out_buffer.pos = 0;
     262             :         }
     263         242 :     } while (in_buffer.pos < in_buffer.size);
     264             : 
     265         242 :     return 1;
     266             : }
     267             : 
     268             : /*
     269             :  * Finish off an encoded strip by flushing it.
     270             :  */
     271         242 : static int ZSTDPostEncode(TIFF *tif)
     272             : {
     273             :     static const char module[] = "ZSTDPostEncode";
     274         242 :     ZSTDState *sp = ZSTDEncoderState(tif);
     275             :     size_t zstd_ret;
     276             : 
     277             :     do
     278             :     {
     279         242 :         zstd_ret = ZSTD_endStream(sp->cstream, &sp->out_buffer);
     280         242 :         if (ZSTD_isError(zstd_ret))
     281             :         {
     282           0 :             TIFFErrorExtR(tif, module, "Error in ZSTD_endStream(): %s",
     283             :                           ZSTD_getErrorName(zstd_ret));
     284           0 :             return 0;
     285             :         }
     286         242 :         if (sp->out_buffer.pos > 0)
     287             :         {
     288         242 :             tif->tif_rawcc = sp->out_buffer.pos;
     289         242 :             if (!TIFFFlushData1(tif))
     290           0 :                 return 0;
     291         242 :             sp->out_buffer.dst = tif->tif_rawcp;
     292         242 :             sp->out_buffer.pos = 0;
     293             :         }
     294         242 :     } while (zstd_ret != 0);
     295         242 :     return 1;
     296             : }
     297             : 
     298         808 : static void ZSTDCleanup(TIFF *tif)
     299             : {
     300         808 :     ZSTDState *sp = GetZSTDState(tif);
     301             : 
     302         808 :     assert(sp != 0);
     303             : 
     304         808 :     (void)TIFFPredictorCleanup(tif);
     305             : 
     306         808 :     tif->tif_tagmethods.vgetfield = sp->vgetparent;
     307         808 :     tif->tif_tagmethods.vsetfield = sp->vsetparent;
     308             : 
     309         808 :     if (sp->dstream)
     310             :     {
     311         141 :         ZSTD_freeDStream(sp->dstream);
     312         141 :         sp->dstream = NULL;
     313             :     }
     314         808 :     if (sp->cstream)
     315             :     {
     316          86 :         ZSTD_freeCStream(sp->cstream);
     317          86 :         sp->cstream = NULL;
     318             :     }
     319         808 :     _TIFFfreeExt(tif, sp);
     320         808 :     tif->tif_data = NULL;
     321             : 
     322         808 :     _TIFFSetDefaultCompressionState(tif);
     323         808 : }
     324             : 
     325        7653 : static int ZSTDVSetField(TIFF *tif, uint32_t tag, va_list ap)
     326             : {
     327             :     static const char module[] = "ZSTDVSetField";
     328        7653 :     ZSTDState *sp = GetZSTDState(tif);
     329             : 
     330        7653 :     switch (tag)
     331             :     {
     332          26 :         case TIFFTAG_ZSTD_LEVEL:
     333          26 :             sp->compression_level = (int)va_arg(ap, int);
     334          52 :             if (sp->compression_level <= 0 ||
     335          26 :                 sp->compression_level > ZSTD_maxCLevel())
     336             :             {
     337           0 :                 TIFFWarningExtR(tif, module,
     338             :                                 "ZSTD_LEVEL should be between 1 and %d",
     339             :                                 ZSTD_maxCLevel());
     340             :             }
     341          26 :             return 1;
     342        7627 :         default:
     343        7627 :             return (*sp->vsetparent)(tif, tag, ap);
     344             :     }
     345             :     /*NOTREACHED*/
     346             : }
     347             : 
     348        7399 : static int ZSTDVGetField(TIFF *tif, uint32_t tag, va_list ap)
     349             : {
     350        7399 :     ZSTDState *sp = GetZSTDState(tif);
     351             : 
     352        7399 :     switch (tag)
     353             :     {
     354           0 :         case TIFFTAG_ZSTD_LEVEL:
     355           0 :             *va_arg(ap, int *) = sp->compression_level;
     356           0 :             break;
     357        7399 :         default:
     358        7399 :             return (*sp->vgetparent)(tif, tag, ap);
     359             :     }
     360           0 :     return 1;
     361             : }
     362             : 
     363             : static const TIFFField ZSTDFields[] = {
     364             :     {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
     365             :      TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "ZSTD compression_level",
     366             :      NULL},
     367             : };
     368             : 
     369         808 : int TIFFInitZSTD(TIFF *tif, int scheme)
     370             : {
     371             :     static const char module[] = "TIFFInitZSTD";
     372             :     ZSTDState *sp;
     373             : 
     374             :     (void)scheme;
     375         808 :     assert(scheme == COMPRESSION_ZSTD);
     376             : 
     377             :     /*
     378             :      * Merge codec-specific tag information.
     379             :      */
     380         808 :     if (!_TIFFMergeFields(tif, ZSTDFields, TIFFArrayCount(ZSTDFields)))
     381             :     {
     382           0 :         TIFFErrorExtR(tif, module, "Merging ZSTD codec-specific tags failed");
     383           0 :         return 0;
     384             :     }
     385             : 
     386             :     /*
     387             :      * Allocate state block so tag methods have storage to record values.
     388             :      */
     389         808 :     tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(ZSTDState));
     390         808 :     if (tif->tif_data == NULL)
     391           0 :         goto bad;
     392         808 :     sp = GetZSTDState(tif);
     393             : 
     394             :     /*
     395             :      * Override parent get/set field methods.
     396             :      */
     397         808 :     sp->vgetparent = tif->tif_tagmethods.vgetfield;
     398         808 :     tif->tif_tagmethods.vgetfield = ZSTDVGetField; /* hook for codec tags */
     399         808 :     sp->vsetparent = tif->tif_tagmethods.vsetfield;
     400         808 :     tif->tif_tagmethods.vsetfield = ZSTDVSetField; /* hook for codec tags */
     401             : 
     402             :     /* Default values for codec-specific fields */
     403         808 :     sp->compression_level = 9; /* default comp. level */
     404         808 :     sp->state = 0;
     405         808 :     sp->dstream = 0;
     406         808 :     sp->cstream = 0;
     407         808 :     sp->out_buffer.dst = NULL;
     408         808 :     sp->out_buffer.size = 0;
     409         808 :     sp->out_buffer.pos = 0;
     410             : 
     411             :     /*
     412             :      * Install codec methods.
     413             :      */
     414         808 :     tif->tif_fixuptags = ZSTDFixupTags;
     415         808 :     tif->tif_setupdecode = ZSTDSetupDecode;
     416         808 :     tif->tif_predecode = ZSTDPreDecode;
     417         808 :     tif->tif_decoderow = ZSTDDecode;
     418         808 :     tif->tif_decodestrip = ZSTDDecode;
     419         808 :     tif->tif_decodetile = ZSTDDecode;
     420         808 :     tif->tif_setupencode = ZSTDSetupEncode;
     421         808 :     tif->tif_preencode = ZSTDPreEncode;
     422         808 :     tif->tif_postencode = ZSTDPostEncode;
     423         808 :     tif->tif_encoderow = ZSTDEncode;
     424         808 :     tif->tif_encodestrip = ZSTDEncode;
     425         808 :     tif->tif_encodetile = ZSTDEncode;
     426         808 :     tif->tif_cleanup = ZSTDCleanup;
     427             :     /*
     428             :      * Setup predictor setup.
     429             :      */
     430         808 :     (void)TIFFPredictorInit(tif);
     431         808 :     return 1;
     432           0 : bad:
     433           0 :     TIFFErrorExtR(tif, module, "No space for ZSTD state block");
     434           0 :     return 0;
     435             : }
     436             : #endif /* ZSTD_SUPPORT */

Generated by: LCOV version 1.14