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

Generated by: LCOV version 1.14