LCOV - code coverage report
Current view: top level - frmts/webp - webpdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 351 485 72.4 %
Date: 2025-08-01 10:10:57 Functions: 17 18 94.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL WEBP Driver
       4             :  * Purpose:  Implement GDAL WEBP Support based on libwebp
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_string.h"
      14             : #include "cpl_vsi_virtual.h"
      15             : #include "gdal_frmts.h"
      16             : #include "gdal_pam.h"
      17             : 
      18             : #include "webp_headers.h"
      19             : #include "webpdrivercore.h"
      20             : 
      21             : #include <limits>
      22             : 
      23             : /************************************************************************/
      24             : /* ==================================================================== */
      25             : /*                               WEBPDataset                            */
      26             : /* ==================================================================== */
      27             : /************************************************************************/
      28             : 
      29             : class WEBPRasterBand;
      30             : 
      31             : class WEBPDataset final : public GDALPamDataset
      32             : {
      33             :     friend class WEBPRasterBand;
      34             : 
      35             :     VSILFILE *fpImage;
      36             :     GByte *pabyUncompressed;
      37             :     int bHasBeenUncompressed;
      38             :     CPLErr eUncompressErrRet;
      39             :     CPLErr Uncompress();
      40             : 
      41             :     int bHasReadXMPMetadata;
      42             : 
      43             :     CPL_DISALLOW_COPY_ASSIGN(WEBPDataset)
      44             : 
      45             :   public:
      46             :     WEBPDataset();
      47             :     virtual ~WEBPDataset();
      48             : 
      49             :     virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
      50             :                              GDALDataType, int, BANDMAP_TYPE,
      51             :                              GSpacing nPixelSpace, GSpacing nLineSpace,
      52             :                              GSpacing nBandSpace,
      53             :                              GDALRasterIOExtraArg *psExtraArg) override;
      54             : 
      55             :     virtual char **GetMetadataDomainList() override;
      56             :     virtual char **GetMetadata(const char *pszDomain = "") override;
      57             : 
      58             :     CPLStringList GetCompressionFormats(int nXOff, int nYOff, int nXSize,
      59             :                                         int nYSize, int nBandCount,
      60             :                                         const int *panBandList) override;
      61             :     CPLErr ReadCompressedData(const char *pszFormat, int nXOff, int nYOff,
      62             :                               int nXSize, int nYSize, int nBandCount,
      63             :                               const int *panBandList, void **ppBuffer,
      64             :                               size_t *pnBufferSize,
      65             :                               char **ppszDetailedFormat) override;
      66             : 
      67             :     static GDALPamDataset *OpenPAM(GDALOpenInfo *poOpenInfo);
      68             :     static GDALDataset *Open(GDALOpenInfo *);
      69             :     static GDALDataset *CreateCopy(const char *pszFilename,
      70             :                                    GDALDataset *poSrcDS, int bStrict,
      71             :                                    char **papszOptions,
      72             :                                    GDALProgressFunc pfnProgress,
      73             :                                    void *pProgressData);
      74             : };
      75             : 
      76             : /************************************************************************/
      77             : /* ==================================================================== */
      78             : /*                            WEBPRasterBand                            */
      79             : /* ==================================================================== */
      80             : /************************************************************************/
      81             : 
      82             : class WEBPRasterBand final : public GDALPamRasterBand
      83             : {
      84             :     friend class WEBPDataset;
      85             : 
      86             :   public:
      87             :     WEBPRasterBand(WEBPDataset *, int);
      88             : 
      89             :     virtual CPLErr IReadBlock(int, int, void *) override;
      90             :     virtual GDALColorInterp GetColorInterpretation() override;
      91             : };
      92             : 
      93             : /************************************************************************/
      94             : /*                          WEBPRasterBand()                            */
      95             : /************************************************************************/
      96             : 
      97        1775 : WEBPRasterBand::WEBPRasterBand(WEBPDataset *poDSIn, int)
      98             : {
      99        1774 :     poDS = poDSIn;
     100             : 
     101        1774 :     eDataType = GDT_Byte;
     102             : 
     103        1774 :     nBlockXSize = poDSIn->nRasterXSize;
     104        1774 :     nBlockYSize = 1;
     105        1774 : }
     106             : 
     107             : /************************************************************************/
     108             : /*                             IReadBlock()                             */
     109             : /************************************************************************/
     110             : 
     111       11676 : CPLErr WEBPRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     112             :                                   void *pImage)
     113             : {
     114       11676 :     WEBPDataset *poGDS = cpl::down_cast<WEBPDataset *>(poDS);
     115             : 
     116       11676 :     if (poGDS->Uncompress() != CE_None)
     117           0 :         return CE_Failure;
     118             : 
     119       11676 :     GByte *pabyUncompressed =
     120       11676 :         &poGDS->pabyUncompressed[nBlockYOff * nRasterXSize * poGDS->nBands +
     121       11676 :                                  nBand - 1];
     122     2885230 :     for (int i = 0; i < nRasterXSize; i++)
     123     2873560 :         reinterpret_cast<GByte *>(pImage)[i] =
     124     2873560 :             pabyUncompressed[poGDS->nBands * i];
     125             : 
     126       11676 :     return CE_None;
     127             : }
     128             : 
     129             : /************************************************************************/
     130             : /*                       GetColorInterpretation()                       */
     131             : /************************************************************************/
     132             : 
     133          81 : GDALColorInterp WEBPRasterBand::GetColorInterpretation()
     134             : 
     135             : {
     136          81 :     if (nBand == 1)
     137          26 :         return GCI_RedBand;
     138             : 
     139          55 :     else if (nBand == 2)
     140          26 :         return GCI_GreenBand;
     141             : 
     142          29 :     else if (nBand == 3)
     143          26 :         return GCI_BlueBand;
     144             : 
     145           3 :     return GCI_AlphaBand;
     146             : }
     147             : 
     148             : /************************************************************************/
     149             : /* ==================================================================== */
     150             : /*                             WEBPDataset                               */
     151             : /* ==================================================================== */
     152             : /************************************************************************/
     153             : 
     154             : /************************************************************************/
     155             : /*                            WEBPDataset()                              */
     156             : /************************************************************************/
     157             : 
     158         487 : WEBPDataset::WEBPDataset()
     159             :     : fpImage(nullptr), pabyUncompressed(nullptr), bHasBeenUncompressed(FALSE),
     160         487 :       eUncompressErrRet(CE_None), bHasReadXMPMetadata(FALSE)
     161             : {
     162         487 : }
     163             : 
     164             : /************************************************************************/
     165             : /*                           ~WEBPDataset()                             */
     166             : /************************************************************************/
     167             : 
     168         974 : WEBPDataset::~WEBPDataset()
     169             : 
     170             : {
     171         486 :     FlushCache(true);
     172         486 :     if (fpImage)
     173         486 :         VSIFCloseL(fpImage);
     174         486 :     VSIFree(pabyUncompressed);
     175         974 : }
     176             : 
     177             : /************************************************************************/
     178             : /*                      GetMetadataDomainList()                         */
     179             : /************************************************************************/
     180             : 
     181           1 : char **WEBPDataset::GetMetadataDomainList()
     182             : {
     183           1 :     return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
     184           1 :                                    TRUE, "xml:XMP", nullptr);
     185             : }
     186             : 
     187             : /************************************************************************/
     188             : /*                           GetMetadata()                              */
     189             : /************************************************************************/
     190             : 
     191          53 : char **WEBPDataset::GetMetadata(const char *pszDomain)
     192             : {
     193          53 :     if ((pszDomain != nullptr && EQUAL(pszDomain, "xml:XMP")) &&
     194           4 :         !bHasReadXMPMetadata)
     195             :     {
     196           4 :         bHasReadXMPMetadata = TRUE;
     197             : 
     198           4 :         VSIFSeekL(fpImage, 12, SEEK_SET);
     199             : 
     200           4 :         bool bFirst = true;
     201             :         while (true)
     202             :         {
     203             :             char szHeader[5];
     204             :             GUInt32 nChunkSize;
     205             : 
     206          16 :             if (VSIFReadL(szHeader, 1, 4, fpImage) != 4 ||
     207           8 :                 VSIFReadL(&nChunkSize, 1, 4, fpImage) != 4)
     208           4 :                 break;
     209             : 
     210           8 :             szHeader[4] = '\0';
     211           8 :             CPL_LSBPTR32(&nChunkSize);
     212             : 
     213           8 :             if (bFirst)
     214             :             {
     215           4 :                 if (strcmp(szHeader, "VP8X") != 0 || nChunkSize < 10)
     216             :                     break;
     217             : 
     218             :                 int l_nFlags;
     219           2 :                 if (VSIFReadL(&l_nFlags, 1, 4, fpImage) != 4)
     220           0 :                     break;
     221           2 :                 CPL_LSBPTR32(&l_nFlags);
     222           2 :                 if ((l_nFlags & 8) == 0)
     223           0 :                     break;
     224             : 
     225           2 :                 VSIFSeekL(fpImage, nChunkSize - 4, SEEK_CUR);
     226             : 
     227           2 :                 bFirst = false;
     228             :             }
     229           4 :             else if (strcmp(szHeader, "META") == 0)
     230             :             {
     231           2 :                 if (nChunkSize > 1024 * 1024)
     232           0 :                     break;
     233             : 
     234             :                 char *pszXMP =
     235           2 :                     reinterpret_cast<char *>(VSIMalloc(nChunkSize + 1));
     236           2 :                 if (pszXMP == nullptr)
     237           0 :                     break;
     238             : 
     239           2 :                 if (static_cast<GUInt32>(VSIFReadL(pszXMP, 1, nChunkSize,
     240           2 :                                                    fpImage)) != nChunkSize)
     241             :                 {
     242           0 :                     VSIFree(pszXMP);
     243           0 :                     break;
     244             :                 }
     245           2 :                 pszXMP[nChunkSize] = '\0';
     246             : 
     247             :                 /* Avoid setting the PAM dirty bit just for that */
     248           2 :                 const int nOldPamFlags = nPamFlags;
     249             : 
     250           2 :                 char *apszMDList[2] = {pszXMP, nullptr};
     251           2 :                 SetMetadata(apszMDList, "xml:XMP");
     252             : 
     253             :                 // cppcheck-suppress redundantAssignment
     254           2 :                 nPamFlags = nOldPamFlags;
     255             : 
     256           2 :                 VSIFree(pszXMP);
     257           2 :                 break;
     258             :             }
     259             :             else
     260           2 :                 VSIFSeekL(fpImage, nChunkSize, SEEK_CUR);
     261           4 :         }
     262             :     }
     263             : 
     264          53 :     return GDALPamDataset::GetMetadata(pszDomain);
     265             : }
     266             : 
     267             : /************************************************************************/
     268             : /*                            Uncompress()                              */
     269             : /************************************************************************/
     270             : 
     271       12011 : CPLErr WEBPDataset::Uncompress()
     272             : {
     273       12011 :     if (bHasBeenUncompressed)
     274       11654 :         return eUncompressErrRet;
     275             : 
     276         357 :     bHasBeenUncompressed = TRUE;
     277         357 :     eUncompressErrRet = CE_Failure;
     278             : 
     279             :     // To avoid excessive memory allocation attempts
     280             :     // Normally WebP images are no larger than 16383x16383*4 ~= 1 GB
     281         357 :     if (nRasterXSize > INT_MAX / (nRasterYSize * nBands))
     282             :     {
     283           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too large image");
     284           0 :         return CE_Failure;
     285             :     }
     286             : 
     287         357 :     pabyUncompressed = reinterpret_cast<GByte *>(
     288         357 :         VSIMalloc3(nRasterXSize, nRasterYSize, nBands));
     289         357 :     if (pabyUncompressed == nullptr)
     290           0 :         return CE_Failure;
     291             : 
     292         357 :     VSIFSeekL(fpImage, 0, SEEK_END);
     293         357 :     vsi_l_offset nSizeLarge = VSIFTellL(fpImage);
     294         357 :     if (nSizeLarge !=
     295         357 :         static_cast<vsi_l_offset>(static_cast<uint32_t>(nSizeLarge)))
     296           0 :         return CE_Failure;
     297         357 :     VSIFSeekL(fpImage, 0, SEEK_SET);
     298         357 :     uint32_t nSize = static_cast<uint32_t>(nSizeLarge);
     299         357 :     uint8_t *pabyCompressed = reinterpret_cast<uint8_t *>(VSIMalloc(nSize));
     300         357 :     if (pabyCompressed == nullptr)
     301           0 :         return CE_Failure;
     302         357 :     VSIFReadL(pabyCompressed, 1, nSize, fpImage);
     303             :     uint8_t *pRet;
     304             : 
     305         357 :     if (nBands == 4)
     306         234 :         pRet = WebPDecodeRGBAInto(pabyCompressed, static_cast<uint32_t>(nSize),
     307         234 :                                   static_cast<uint8_t *>(pabyUncompressed),
     308         234 :                                   static_cast<size_t>(nRasterXSize) *
     309         234 :                                       nRasterYSize * nBands,
     310         234 :                                   nRasterXSize * nBands);
     311             :     else
     312         123 :         pRet = WebPDecodeRGBInto(pabyCompressed, static_cast<uint32_t>(nSize),
     313         123 :                                  static_cast<uint8_t *>(pabyUncompressed),
     314         123 :                                  static_cast<size_t>(nRasterXSize) *
     315         123 :                                      nRasterYSize * nBands,
     316         123 :                                  nRasterXSize * nBands);
     317             : 
     318         357 :     VSIFree(pabyCompressed);
     319         357 :     if (pRet == nullptr)
     320             :     {
     321           1 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPDecodeRGBInto() failed");
     322           0 :         return CE_Failure;
     323             :     }
     324         356 :     eUncompressErrRet = CE_None;
     325             : 
     326         356 :     return CE_None;
     327             : }
     328             : 
     329             : /************************************************************************/
     330             : /*                             IRasterIO()                              */
     331             : /************************************************************************/
     332             : 
     333         339 : CPLErr WEBPDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     334             :                               int nXSize, int nYSize, void *pData,
     335             :                               int nBufXSize, int nBufYSize,
     336             :                               GDALDataType eBufType, int nBandCount,
     337             :                               BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
     338             :                               GSpacing nLineSpace, GSpacing nBandSpace,
     339             :                               GDALRasterIOExtraArg *psExtraArg)
     340             : 
     341             : {
     342         339 :     if ((eRWFlag == GF_Read) && (nBandCount == nBands) && (nXOff == 0) &&
     343         339 :         (nYOff == 0) && (nXSize == nBufXSize) && (nXSize == nRasterXSize) &&
     344         335 :         (nYSize == nBufYSize) && (nYSize == nRasterYSize) &&
     345        1013 :         (eBufType == GDT_Byte) && (pData != nullptr) &&
     346         335 :         IsAllBands(nBandCount, panBandMap))
     347             :     {
     348         335 :         if (Uncompress() != CE_None)
     349           0 :             return CE_Failure;
     350         335 :         if (nPixelSpace == nBands && nLineSpace == (nPixelSpace * nXSize) &&
     351             :             nBandSpace == 1)
     352             :         {
     353          94 :             memcpy(pData, pabyUncompressed,
     354          94 :                    static_cast<size_t>(nBands) * nXSize * nYSize);
     355             :         }
     356             :         else
     357             :         {
     358        8025 :             for (int y = 0; y < nYSize; ++y)
     359             :             {
     360        7784 :                 GByte *pabyScanline = pabyUncompressed + y * nBands * nXSize;
     361     1101290 :                 for (int x = 0; x < nXSize; ++x)
     362             :                 {
     363     5276670 :                     for (int iBand = 0; iBand < nBands; iBand++)
     364             :                         reinterpret_cast<GByte *>(
     365     4183170 :                             pData)[(y * nLineSpace) + (x * nPixelSpace) +
     366     4183170 :                                    iBand * nBandSpace] =
     367     4183170 :                             pabyScanline[x * nBands + iBand];
     368             :                 }
     369             :             }
     370             :         }
     371             : 
     372         335 :         return CE_None;
     373             :     }
     374             : 
     375           4 :     return GDALPamDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     376             :                                      pData, nBufXSize, nBufYSize, eBufType,
     377             :                                      nBandCount, panBandMap, nPixelSpace,
     378           4 :                                      nLineSpace, nBandSpace, psExtraArg);
     379             : }
     380             : 
     381             : /************************************************************************/
     382             : /*                       GetCompressionFormats()                        */
     383             : /************************************************************************/
     384             : 
     385           0 : CPLStringList WEBPDataset::GetCompressionFormats(int nXOff, int nYOff,
     386             :                                                  int nXSize, int nYSize,
     387             :                                                  int nBandCount,
     388             :                                                  const int *panBandList)
     389             : {
     390           0 :     CPLStringList aosRet;
     391           0 :     if (nXOff == 0 && nYOff == 0 && nXSize == nRasterXSize &&
     392           0 :         nYSize == nRasterYSize && IsAllBands(nBandCount, panBandList))
     393             :     {
     394           0 :         aosRet.AddString("WEBP");
     395             :     }
     396           0 :     return aosRet;
     397             : }
     398             : 
     399             : /************************************************************************/
     400             : /*                       ReadCompressedData()                           */
     401             : /************************************************************************/
     402             : 
     403           2 : CPLErr WEBPDataset::ReadCompressedData(const char *pszFormat, int nXOff,
     404             :                                        int nYOff, int nXSize, int nYSize,
     405             :                                        int nBandCount, const int *panBandList,
     406             :                                        void **ppBuffer, size_t *pnBufferSize,
     407             :                                        char **ppszDetailedFormat)
     408             : {
     409           2 :     if (nXOff == 0 && nYOff == 0 && nXSize == nRasterXSize &&
     410           4 :         nYSize == nRasterYSize && IsAllBands(nBandCount, panBandList))
     411             :     {
     412           2 :         const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
     413           2 :         if (aosTokens.size() != 1)
     414           0 :             return CE_Failure;
     415             : 
     416           2 :         if (EQUAL(aosTokens[0], "WEBP"))
     417             :         {
     418           2 :             if (ppszDetailedFormat)
     419           0 :                 *ppszDetailedFormat = VSIStrdup("WEBP");
     420           2 :             VSIFSeekL(fpImage, 0, SEEK_END);
     421           2 :             const auto nFileSize = VSIFTellL(fpImage);
     422           2 :             if (nFileSize > std::numeric_limits<uint32_t>::max())
     423           0 :                 return CE_Failure;
     424           2 :             auto nSize = static_cast<uint32_t>(nFileSize);
     425           2 :             if (ppBuffer)
     426             :             {
     427           2 :                 if (!pnBufferSize)
     428           0 :                     return CE_Failure;
     429           2 :                 bool bFreeOnError = false;
     430           2 :                 if (*ppBuffer)
     431             :                 {
     432           0 :                     if (*pnBufferSize < nSize)
     433           0 :                         return CE_Failure;
     434             :                 }
     435             :                 else
     436             :                 {
     437           2 :                     *ppBuffer = VSI_MALLOC_VERBOSE(nSize);
     438           2 :                     if (*ppBuffer == nullptr)
     439           0 :                         return CE_Failure;
     440           2 :                     bFreeOnError = true;
     441             :                 }
     442           2 :                 VSIFSeekL(fpImage, 0, SEEK_SET);
     443           2 :                 if (VSIFReadL(*ppBuffer, nSize, 1, fpImage) != 1)
     444             :                 {
     445           0 :                     if (bFreeOnError)
     446             :                     {
     447           0 :                         VSIFree(*ppBuffer);
     448           0 :                         *ppBuffer = nullptr;
     449             :                     }
     450           0 :                     return CE_Failure;
     451             :                 }
     452             : 
     453             :                 // Remove META box
     454           2 :                 if (nSize > 12 && memcmp(*ppBuffer, "RIFF", 4) == 0)
     455             :                 {
     456           2 :                     size_t nPos = 12;
     457           2 :                     GByte *pabyData = static_cast<GByte *>(*ppBuffer);
     458           6 :                     while (nPos <= nSize - 8)
     459             :                     {
     460           4 :                         char szBoxName[5] = {0, 0, 0, 0, 0};
     461           4 :                         memcpy(szBoxName, pabyData + nPos, 4);
     462             :                         uint32_t nChunkSize;
     463           4 :                         memcpy(&nChunkSize, pabyData + nPos + 4, 4);
     464           4 :                         CPL_LSBPTR32(&nChunkSize);
     465           4 :                         if (nChunkSize % 2)  // Payload padding if needed
     466           1 :                             nChunkSize++;
     467           4 :                         if (nChunkSize > nSize - (nPos + 8))
     468           0 :                             break;
     469           4 :                         if (memcmp(szBoxName, "META", 4) == 0)
     470             :                         {
     471           1 :                             CPLDebug("WEBP",
     472             :                                      "Remove existing %s box from "
     473             :                                      "source compressed data",
     474             :                                      szBoxName);
     475           1 :                             if (nPos + 8 + nChunkSize < nSize)
     476             :                             {
     477           0 :                                 memmove(pabyData + nPos,
     478           0 :                                         pabyData + nPos + 8 + nChunkSize,
     479           0 :                                         nSize - (nPos + 8 + nChunkSize));
     480             :                             }
     481           1 :                             nSize -= 8 + nChunkSize;
     482             :                         }
     483             :                         else
     484             :                         {
     485           3 :                             nPos += 8 + nChunkSize;
     486             :                         }
     487             :                     }
     488             : 
     489             :                     // Patch size of RIFF
     490           2 :                     uint32_t nSize32 = nSize - 8;
     491           2 :                     CPL_LSBPTR32(&nSize32);
     492           2 :                     memcpy(pabyData + 4, &nSize32, 4);
     493             :                 }
     494             :             }
     495           2 :             if (pnBufferSize)
     496           2 :                 *pnBufferSize = nSize;
     497           2 :             return CE_None;
     498             :         }
     499             :     }
     500           0 :     return CE_Failure;
     501             : }
     502             : 
     503             : /************************************************************************/
     504             : /*                          OpenPAM()                                   */
     505             : /************************************************************************/
     506             : 
     507         487 : GDALPamDataset *WEBPDataset::OpenPAM(GDALOpenInfo *poOpenInfo)
     508             : 
     509             : {
     510         487 :     if (!WEBPDriverIdentify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     511           0 :         return nullptr;
     512             : 
     513             :     int nWidth, nHeight;
     514         487 :     if (!WebPGetInfo(reinterpret_cast<const uint8_t *>(poOpenInfo->pabyHeader),
     515         487 :                      static_cast<uint32_t>(poOpenInfo->nHeaderBytes), &nWidth,
     516             :                      &nHeight))
     517           0 :         return nullptr;
     518             : 
     519         487 :     int nBands = 3;
     520             : 
     521         974 :     auto poDS = std::make_unique<WEBPDataset>();
     522             : 
     523             : #if WEBP_DECODER_ABI_VERSION >= 0x0002
     524             :     WebPDecoderConfig config;
     525         487 :     if (!WebPInitDecoderConfig(&config))
     526           0 :         return nullptr;
     527             : 
     528             :     const bool bOK =
     529         487 :         WebPGetFeatures(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes,
     530         487 :                         &config.input) == VP8_STATUS_OK;
     531             : 
     532             :     // Cf commit https://github.com/webmproject/libwebp/commit/86c0031eb2c24f78d4dcfc5dab752ebc9f511607#diff-859d219dccb3163cc11cd538effed461ff0145135070abfe70bd263f16408023
     533             :     // Added in webp 0.4.0
     534             : #if WEBP_DECODER_ABI_VERSION >= 0x0202
     535         974 :     poDS->GDALDataset::SetMetadataItem(
     536             :         "COMPRESSION_REVERSIBILITY",
     537         487 :         config.input.format == 2 ? "LOSSLESS" : "LOSSY", "IMAGE_STRUCTURE");
     538             : #endif
     539             : 
     540         678 :     if (config.input.has_alpha ||
     541         191 :         CPLTestBool(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
     542             :                                          "FORCE_4BANDS", "NO")))
     543         314 :         nBands = 4;
     544             : 
     545         487 :     WebPFreeDecBuffer(&config.output);
     546             : 
     547         487 :     if (!bOK)
     548           0 :         return nullptr;
     549             : 
     550             : #endif
     551             : 
     552         487 :     if (poOpenInfo->eAccess == GA_Update)
     553             :     {
     554           0 :         ReportUpdateNotSupportedByDriver("WEBP");
     555           0 :         return nullptr;
     556             :     }
     557             : 
     558             :     /* -------------------------------------------------------------------- */
     559             :     /*      Create a corresponding GDALDataset.                             */
     560             :     /* -------------------------------------------------------------------- */
     561         487 :     poDS->nRasterXSize = nWidth;
     562         487 :     poDS->nRasterYSize = nHeight;
     563         487 :     poDS->fpImage = poOpenInfo->fpL;
     564         487 :     poOpenInfo->fpL = nullptr;
     565             : 
     566             :     /* -------------------------------------------------------------------- */
     567             :     /*      Create band information objects.                                */
     568             :     /* -------------------------------------------------------------------- */
     569        2262 :     for (int iBand = 0; iBand < nBands; iBand++)
     570        1775 :         poDS->SetBand(iBand + 1, new WEBPRasterBand(poDS.get(), iBand + 1));
     571             : 
     572             :     /* -------------------------------------------------------------------- */
     573             :     /*      Initialize any PAM information.                                 */
     574             :     /* -------------------------------------------------------------------- */
     575         487 :     poDS->SetDescription(poOpenInfo->pszFilename);
     576             : 
     577         487 :     poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
     578             : 
     579             :     /* -------------------------------------------------------------------- */
     580             :     /*      Open overviews.                                                 */
     581             :     /* -------------------------------------------------------------------- */
     582         974 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename,
     583         487 :                                 poOpenInfo->GetSiblingFiles());
     584             : 
     585         487 :     return poDS.release();
     586             : }
     587             : 
     588             : /************************************************************************/
     589             : /*                             Open()                                   */
     590             : /************************************************************************/
     591             : 
     592         381 : GDALDataset *WEBPDataset::Open(GDALOpenInfo *poOpenInfo)
     593             : 
     594             : {
     595         381 :     return OpenPAM(poOpenInfo);
     596             : }
     597             : 
     598             : /************************************************************************/
     599             : /*                              WebPUserData                            */
     600             : /************************************************************************/
     601             : 
     602             : typedef struct
     603             : {
     604             :     VSILFILE *fp;
     605             :     GDALProgressFunc pfnProgress;
     606             :     void *pProgressData;
     607             : } WebPUserData;
     608             : 
     609             : /************************************************************************/
     610             : /*                         WEBPDatasetWriter()                          */
     611             : /************************************************************************/
     612             : 
     613         849 : static int WEBPDatasetWriter(const uint8_t *data, size_t data_size,
     614             :                              const WebPPicture *const picture)
     615             : {
     616         849 :     WebPUserData *pUserData =
     617             :         reinterpret_cast<WebPUserData *>(picture->custom_ptr);
     618         849 :     return VSIFWriteL(data, 1, data_size, pUserData->fp) == data_size;
     619             : }
     620             : 
     621             : /************************************************************************/
     622             : /*                        WEBPDatasetProgressHook()                     */
     623             : /************************************************************************/
     624             : 
     625             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     626        1005 : static int WEBPDatasetProgressHook(int percent,
     627             :                                    const WebPPicture *const picture)
     628             : {
     629        1005 :     WebPUserData *pUserData =
     630             :         reinterpret_cast<WebPUserData *>(picture->custom_ptr);
     631        1005 :     return pUserData->pfnProgress(percent / 100.0, nullptr,
     632        1005 :                                   pUserData->pProgressData);
     633             : }
     634             : #endif
     635             : 
     636             : /************************************************************************/
     637             : /*                              CreateCopy()                            */
     638             : /************************************************************************/
     639             : 
     640         133 : GDALDataset *WEBPDataset::CreateCopy(const char *pszFilename,
     641             :                                      GDALDataset *poSrcDS, int bStrict,
     642             :                                      char **papszOptions,
     643             :                                      GDALProgressFunc pfnProgress,
     644             :                                      void *pProgressData)
     645             : 
     646             : {
     647             :     const char *pszLossLessCopy =
     648         133 :         CSLFetchNameValueDef(papszOptions, "LOSSLESS_COPY", "AUTO");
     649         133 :     if (EQUAL(pszLossLessCopy, "AUTO") || CPLTestBool(pszLossLessCopy))
     650             :     {
     651         133 :         void *pWEBPContent = nullptr;
     652         133 :         size_t nWEBPContent = 0;
     653         133 :         if (poSrcDS->ReadCompressedData(
     654             :                 "WEBP", 0, 0, poSrcDS->GetRasterXSize(),
     655             :                 poSrcDS->GetRasterYSize(), poSrcDS->GetRasterCount(), nullptr,
     656         266 :                 &pWEBPContent, &nWEBPContent, nullptr) == CE_None)
     657             :         {
     658           2 :             CPLDebug("WEBP", "Lossless copy from source dataset");
     659           2 :             std::vector<GByte> abyData;
     660             :             try
     661             :             {
     662           2 :                 abyData.assign(static_cast<const GByte *>(pWEBPContent),
     663           2 :                                static_cast<const GByte *>(pWEBPContent) +
     664           2 :                                    nWEBPContent);
     665             : 
     666           2 :                 char **papszXMP = poSrcDS->GetMetadata("xml:XMP");
     667           2 :                 if (papszXMP && papszXMP[0])
     668             :                 {
     669             :                     GByte abyChunkHeader[8];
     670           1 :                     memcpy(abyChunkHeader, "META", 4);
     671           1 :                     const size_t nXMPSize = strlen(papszXMP[0]);
     672           1 :                     uint32_t nChunkSize = static_cast<uint32_t>(nXMPSize);
     673           1 :                     CPL_LSBPTR32(&nChunkSize);
     674           1 :                     memcpy(abyChunkHeader + 4, &nChunkSize, 4);
     675           0 :                     abyData.insert(abyData.end(), abyChunkHeader,
     676           1 :                                    abyChunkHeader + sizeof(abyChunkHeader));
     677             :                     abyData.insert(
     678           0 :                         abyData.end(), reinterpret_cast<GByte *>(papszXMP[0]),
     679           1 :                         reinterpret_cast<GByte *>(papszXMP[0]) + nXMPSize);
     680           1 :                     if ((abyData.size() % 2) != 0)  // Payload padding if needed
     681           1 :                         abyData.push_back(0);
     682             : 
     683             :                     // Patch size of RIFF
     684             :                     uint32_t nSize32 =
     685           1 :                         static_cast<uint32_t>(abyData.size()) - 8;
     686           1 :                     CPL_LSBPTR32(&nSize32);
     687           1 :                     memcpy(abyData.data() + 4, &nSize32, 4);
     688             :                 }
     689             :             }
     690           0 :             catch (const std::exception &e)
     691             :             {
     692           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Exception occurred: %s",
     693           0 :                          e.what());
     694           0 :                 abyData.clear();
     695             :             }
     696           2 :             VSIFree(pWEBPContent);
     697             : 
     698           2 :             if (!abyData.empty())
     699             :             {
     700             :                 VSIVirtualHandleUniquePtr fpImage(
     701           2 :                     CPLTestBool(CSLFetchNameValueDef(
     702             :                         papszOptions, "@CREATE_ONLY_VISIBLE_AT_CLOSE_TIME",
     703             :                         "NO"))
     704           0 :                         ? VSIFileManager::GetHandler(pszFilename)
     705           0 :                               ->CreateOnlyVisibleAtCloseTime(pszFilename, true,
     706           0 :                                                              nullptr)
     707           4 :                         : VSIFOpenL(pszFilename, "wb"));
     708           2 :                 if (fpImage == nullptr)
     709             :                 {
     710           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
     711             :                              "Unable to create jpeg file %s.", pszFilename);
     712             : 
     713           0 :                     return nullptr;
     714             :                 }
     715           4 :                 if (fpImage->Write(abyData.data(), 1, abyData.size()) !=
     716           2 :                     abyData.size())
     717             :                 {
     718           0 :                     CPLError(CE_Failure, CPLE_FileIO,
     719           0 :                              "Failure writing data: %s", VSIStrerror(errno));
     720           0 :                     fpImage->CancelCreation();
     721           0 :                     return nullptr;
     722             :                 }
     723             : 
     724           2 :                 if (fpImage->Close() != 0)
     725             :                 {
     726           0 :                     CPLError(CE_Failure, CPLE_FileIO,
     727             :                              "Error at file closing of '%s': %s", pszFilename,
     728           0 :                              VSIStrerror(errno));
     729           0 :                     return nullptr;
     730             :                 }
     731             : 
     732           2 :                 pfnProgress(1.0, nullptr, pProgressData);
     733             : 
     734             :                 // Re-open file and clone missing info to PAM
     735           2 :                 GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     736           2 :                 auto poDS = OpenPAM(&oOpenInfo);
     737           2 :                 if (poDS)
     738             :                 {
     739           2 :                     poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
     740             :                 }
     741             : 
     742           2 :                 return poDS;
     743             :             }
     744             :         }
     745             :     }
     746             : 
     747         131 :     const bool bLossless = CPLFetchBool(papszOptions, "LOSSLESS", false);
     748         253 :     if (!bLossless &&
     749         122 :         (!EQUAL(pszLossLessCopy, "AUTO") && CPLTestBool(pszLossLessCopy)))
     750             :     {
     751           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     752             :                  "LOSSLESS_COPY=YES requested but not possible");
     753           0 :         return nullptr;
     754             :     }
     755             : 
     756             :     /* -------------------------------------------------------------------- */
     757             :     /*      WEBP library initialization                                     */
     758             :     /* -------------------------------------------------------------------- */
     759             : 
     760             :     WebPPicture sPicture;
     761         131 :     if (!WebPPictureInit(&sPicture))
     762             :     {
     763           0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureInit() failed");
     764           0 :         return nullptr;
     765             :     }
     766             : 
     767             :     /* -------------------------------------------------------------------- */
     768             :     /*      Some some rudimentary checks                                    */
     769             :     /* -------------------------------------------------------------------- */
     770             : 
     771         131 :     const int nXSize = poSrcDS->GetRasterXSize();
     772         131 :     const int nYSize = poSrcDS->GetRasterYSize();
     773         131 :     if (nXSize > 16383 || nYSize > 16383)
     774             :     {
     775           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     776             :                  "WEBP maximum image dimensions are 16383 x 16383.");
     777             : 
     778           0 :         return nullptr;
     779             :     }
     780             : 
     781         131 :     const int nBands = poSrcDS->GetRasterCount();
     782         131 :     if (nBands != 3
     783             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     784          96 :         && nBands != 4
     785             : #endif
     786             :     )
     787             :     {
     788          14 :         CPLError(CE_Failure, CPLE_NotSupported,
     789             :                  "WEBP driver doesn't support %d bands. Must be 3 (RGB) "
     790             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     791             :                  "or 4 (RGBA) "
     792             : #endif
     793             :                  "bands.",
     794             :                  nBands);
     795             : 
     796          14 :         return nullptr;
     797             :     }
     798             : 
     799         117 :     const GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
     800             : 
     801         117 :     if (eDT != GDT_Byte)
     802             :     {
     803           0 :         CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
     804             :                  "WEBP driver doesn't support data type %s. "
     805             :                  "Only eight bit byte bands supported.",
     806             :                  GDALGetDataTypeName(
     807             :                      poSrcDS->GetRasterBand(1)->GetRasterDataType()));
     808             : 
     809           0 :         if (bStrict)
     810           0 :             return nullptr;
     811             :     }
     812             : 
     813             :     /* -------------------------------------------------------------------- */
     814             :     /*      What options has the user selected?                             */
     815             :     /* -------------------------------------------------------------------- */
     816         117 :     float fQuality = 75.0f;
     817         117 :     const char *pszQUALITY = CSLFetchNameValue(papszOptions, "QUALITY");
     818         117 :     if (pszQUALITY != nullptr)
     819             :     {
     820          91 :         fQuality = static_cast<float>(CPLAtof(pszQUALITY));
     821          91 :         if (fQuality < 0.0f || fQuality > 100.0f)
     822             :         {
     823           0 :             CPLError(CE_Failure, CPLE_IllegalArg, "%s=%s is not a legal value.",
     824             :                      "QUALITY", pszQUALITY);
     825           0 :             return nullptr;
     826             :         }
     827             :     }
     828             : 
     829         117 :     WebPPreset nPreset = WEBP_PRESET_DEFAULT;
     830             :     const char *pszPRESET =
     831         117 :         CSLFetchNameValueDef(papszOptions, "PRESET", "DEFAULT");
     832         117 :     if (EQUAL(pszPRESET, "DEFAULT"))
     833         117 :         nPreset = WEBP_PRESET_DEFAULT;
     834           0 :     else if (EQUAL(pszPRESET, "PICTURE"))
     835           0 :         nPreset = WEBP_PRESET_PICTURE;
     836           0 :     else if (EQUAL(pszPRESET, "PHOTO"))
     837           0 :         nPreset = WEBP_PRESET_PHOTO;
     838           0 :     else if (EQUAL(pszPRESET, "PICTURE"))
     839           0 :         nPreset = WEBP_PRESET_PICTURE;
     840           0 :     else if (EQUAL(pszPRESET, "DRAWING"))
     841           0 :         nPreset = WEBP_PRESET_DRAWING;
     842           0 :     else if (EQUAL(pszPRESET, "ICON"))
     843           0 :         nPreset = WEBP_PRESET_ICON;
     844           0 :     else if (EQUAL(pszPRESET, "TEXT"))
     845           0 :         nPreset = WEBP_PRESET_TEXT;
     846             :     else
     847             :     {
     848           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "%s=%s is not a legal value.",
     849             :                  "PRESET", pszPRESET);
     850           0 :         return nullptr;
     851             :     }
     852             : 
     853             :     WebPConfig sConfig;
     854         117 :     if (!WebPConfigInitInternal(&sConfig, nPreset, fQuality,
     855             :                                 WEBP_ENCODER_ABI_VERSION))
     856             :     {
     857           0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPConfigInit() failed");
     858           0 :         return nullptr;
     859             :     }
     860             : 
     861             :     // TODO: Get rid of this macro in a reasonable way.
     862             : #define FETCH_AND_SET_OPTION_INT(name, fieldname, minval, maxval)              \
     863             :     {                                                                          \
     864             :         const char *pszVal = CSLFetchNameValue(papszOptions, name);            \
     865             :         if (pszVal != nullptr)                                                 \
     866             :         {                                                                      \
     867             :             sConfig.fieldname = atoi(pszVal);                                  \
     868             :             if (sConfig.fieldname < minval || sConfig.fieldname > maxval)      \
     869             :             {                                                                  \
     870             :                 CPLError(CE_Failure, CPLE_IllegalArg,                          \
     871             :                          "%s=%s is not a legal value.", name, pszVal);         \
     872             :                 return nullptr;                                                \
     873             :             }                                                                  \
     874             :         }                                                                      \
     875             :     }
     876             : 
     877         117 :     FETCH_AND_SET_OPTION_INT("TARGETSIZE", target_size, 0, INT_MAX - 1);
     878             : 
     879         117 :     const char *pszPSNR = CSLFetchNameValue(papszOptions, "PSNR");
     880         117 :     if (pszPSNR)
     881             :     {
     882           0 :         sConfig.target_PSNR = static_cast<float>(CPLAtof(pszPSNR));
     883           0 :         if (sConfig.target_PSNR < 0)
     884             :         {
     885           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
     886             :                      "PSNR=%s is not a legal value.", pszPSNR);
     887           0 :             return nullptr;
     888             :         }
     889             :     }
     890             : 
     891         117 :     FETCH_AND_SET_OPTION_INT("METHOD", method, 0, 6);
     892         117 :     FETCH_AND_SET_OPTION_INT("SEGMENTS", segments, 1, 4);
     893         117 :     FETCH_AND_SET_OPTION_INT("SNS_STRENGTH", sns_strength, 0, 100);
     894         117 :     FETCH_AND_SET_OPTION_INT("FILTER_STRENGTH", filter_strength, 0, 100);
     895         117 :     FETCH_AND_SET_OPTION_INT("FILTER_SHARPNESS", filter_sharpness, 0, 7);
     896         117 :     FETCH_AND_SET_OPTION_INT("FILTER_TYPE", filter_type, 0, 1);
     897         117 :     FETCH_AND_SET_OPTION_INT("AUTOFILTER", autofilter, 0, 1);
     898         117 :     FETCH_AND_SET_OPTION_INT("PASS", pass, 1, 10);
     899         117 :     FETCH_AND_SET_OPTION_INT("PREPROCESSING", preprocessing, 0, 1);
     900         117 :     FETCH_AND_SET_OPTION_INT("PARTITIONS", partitions, 0, 3);
     901             : #if WEBP_ENCODER_ABI_VERSION >= 0x0002
     902         117 :     FETCH_AND_SET_OPTION_INT("PARTITION_LIMIT", partition_limit, 0, 100);
     903             : #endif
     904             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     905         117 :     sConfig.lossless = bLossless;
     906         117 :     if (sConfig.lossless)
     907           9 :         sPicture.use_argb = 1;
     908             : #endif
     909             : #if WEBP_ENCODER_ABI_VERSION >= 0x0209
     910         117 :     FETCH_AND_SET_OPTION_INT("EXACT", exact, 0, 1);
     911             : #endif
     912             : 
     913         117 :     if (!WebPValidateConfig(&sConfig))
     914             :     {
     915           0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPValidateConfig() failed");
     916           0 :         return nullptr;
     917             :     }
     918             : 
     919             :     /* -------------------------------------------------------------------- */
     920             :     /*      Allocate memory                                                 */
     921             :     /* -------------------------------------------------------------------- */
     922             :     GByte *pabyBuffer =
     923         117 :         static_cast<GByte *>(VSI_MALLOC3_VERBOSE(nBands, nXSize, nYSize));
     924         117 :     if (pabyBuffer == nullptr)
     925             :     {
     926           0 :         return nullptr;
     927             :     }
     928             : 
     929             :     /* -------------------------------------------------------------------- */
     930             :     /*      Create the dataset.                                             */
     931             :     /* -------------------------------------------------------------------- */
     932             :     VSIVirtualHandleUniquePtr fpImage(
     933         117 :         CPLTestBool(CSLFetchNameValueDef(
     934             :             papszOptions, "@CREATE_ONLY_VISIBLE_AT_CLOSE_TIME", "NO"))
     935           1 :             ? VSIFileManager::GetHandler(pszFilename)
     936           1 :                   ->CreateOnlyVisibleAtCloseTime(pszFilename, true, nullptr)
     937         235 :             : VSIFOpenL(pszFilename, "wb"));
     938         117 :     if (fpImage == nullptr)
     939             :     {
     940           3 :         CPLError(CE_Failure, CPLE_OpenFailed,
     941             :                  "Unable to create WEBP file %s.\n", pszFilename);
     942           3 :         VSIFree(pabyBuffer);
     943           3 :         return nullptr;
     944             :     }
     945             : 
     946             :     WebPUserData sUserData;
     947         114 :     sUserData.fp = fpImage.get();
     948         114 :     sUserData.pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
     949         114 :     sUserData.pProgressData = pProgressData;
     950             : 
     951             :     /* -------------------------------------------------------------------- */
     952             :     /*      WEBP library settings                                           */
     953             :     /* -------------------------------------------------------------------- */
     954             : 
     955         114 :     sPicture.width = nXSize;
     956         114 :     sPicture.height = nYSize;
     957         114 :     sPicture.writer = WEBPDatasetWriter;
     958         114 :     sPicture.custom_ptr = &sUserData;
     959             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     960         114 :     sPicture.progress_hook = WEBPDatasetProgressHook;
     961             : #endif
     962         114 :     if (!WebPPictureAlloc(&sPicture))
     963             :     {
     964           0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureAlloc() failed");
     965           0 :         VSIFree(pabyBuffer);
     966           0 :         fpImage->CancelCreation();
     967           0 :         return nullptr;
     968             :     }
     969             : 
     970             :     /* -------------------------------------------------------------------- */
     971             :     /*      Acquire source imagery.                                         */
     972             :     /* -------------------------------------------------------------------- */
     973             :     CPLErr eErr =
     974         228 :         poSrcDS->RasterIO(GF_Read, 0, 0, nXSize, nYSize, pabyBuffer, nXSize,
     975             :                           nYSize, GDT_Byte, nBands, nullptr, nBands,
     976         114 :                           static_cast<GSpacing>(nBands) * nXSize, 1, nullptr);
     977             : 
     978             : /* -------------------------------------------------------------------- */
     979             : /*      Import and write to file                                        */
     980             : /* -------------------------------------------------------------------- */
     981             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     982         114 :     if (eErr == CE_None && nBands == 4)
     983             :     {
     984          82 :         if (!WebPPictureImportRGBA(&sPicture, pabyBuffer, nBands * nXSize))
     985             :         {
     986           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     987             :                      "WebPPictureImportRGBA() failed");
     988           0 :             eErr = CE_Failure;
     989             :         }
     990             :     }
     991             :     else
     992             : #endif
     993          64 :         if (eErr == CE_None &&
     994          32 :             !WebPPictureImportRGB(&sPicture, pabyBuffer, nBands * nXSize))
     995             :     {
     996           0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureImportRGB() failed");
     997           0 :         eErr = CE_Failure;
     998             :     }
     999             : 
    1000         114 :     if (pfnProgress)
    1001         114 :         pfnProgress(0.5, "", pProgressData);
    1002             : 
    1003         114 :     if (eErr == CE_None && !WebPEncode(&sConfig, &sPicture))
    1004             :     {
    1005             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
    1006          10 :         const char *pszErrorMsg = nullptr;
    1007          10 :         switch (sPicture.error_code)
    1008             :         {
    1009           0 :             case VP8_ENC_ERROR_OUT_OF_MEMORY:
    1010           0 :                 pszErrorMsg = "Out of memory";
    1011           0 :                 break;
    1012           0 :             case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
    1013           0 :                 pszErrorMsg = "Out of memory while flushing bits";
    1014           0 :                 break;
    1015           0 :             case VP8_ENC_ERROR_NULL_PARAMETER:
    1016           0 :                 pszErrorMsg = "A pointer parameter is NULL";
    1017           0 :                 break;
    1018           0 :             case VP8_ENC_ERROR_INVALID_CONFIGURATION:
    1019           0 :                 pszErrorMsg = "Configuration is invalid";
    1020           0 :                 break;
    1021           0 :             case VP8_ENC_ERROR_BAD_DIMENSION:
    1022           0 :                 pszErrorMsg = "Picture has invalid width/height";
    1023           0 :                 break;
    1024           0 :             case VP8_ENC_ERROR_PARTITION0_OVERFLOW:
    1025           0 :                 pszErrorMsg = "Partition is bigger than 512k. Try using less "
    1026             :                               "SEGMENTS, or increase PARTITION_LIMIT value";
    1027           0 :                 break;
    1028           0 :             case VP8_ENC_ERROR_PARTITION_OVERFLOW:
    1029           0 :                 pszErrorMsg = "Partition is bigger than 16M";
    1030           0 :                 break;
    1031           5 :             case VP8_ENC_ERROR_BAD_WRITE:
    1032           5 :                 pszErrorMsg = "Error while flushing bytes";
    1033           5 :                 break;
    1034           0 :             case VP8_ENC_ERROR_FILE_TOO_BIG:
    1035           0 :                 pszErrorMsg = "File is bigger than 4G";
    1036           0 :                 break;
    1037           0 :             case VP8_ENC_ERROR_USER_ABORT:
    1038           0 :                 pszErrorMsg = "User interrupted";
    1039           0 :                 break;
    1040           5 :             default:
    1041           5 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1042             :                          "WebPEncode returned an unknown error code: %d",
    1043           5 :                          sPicture.error_code);
    1044           5 :                 pszErrorMsg = "Unknown WebP error type.";
    1045           5 :                 break;
    1046             :         }
    1047          10 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed : %s",
    1048             :                  pszErrorMsg);
    1049             : #else
    1050             :         CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed");
    1051             : #endif
    1052          10 :         eErr = CE_Failure;
    1053             :     }
    1054             : 
    1055             :     /* -------------------------------------------------------------------- */
    1056             :     /*      Cleanup and close.                                              */
    1057             :     /* -------------------------------------------------------------------- */
    1058         114 :     CPLFree(pabyBuffer);
    1059             : 
    1060         114 :     WebPPictureFree(&sPicture);
    1061             : 
    1062         114 :     if (eErr == CE_None)
    1063             :     {
    1064         104 :         if (fpImage->Close() != 0)
    1065             :         {
    1066           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1067             :                      "Error at file closing of '%s': %s", pszFilename,
    1068           0 :                      VSIStrerror(errno));
    1069           0 :             eErr = CE_Failure;
    1070             :         }
    1071             :     }
    1072             :     else
    1073             :     {
    1074          10 :         fpImage->CancelCreation();
    1075          10 :         fpImage.reset();
    1076             :     }
    1077             : 
    1078         114 :     if (pfnProgress)
    1079         114 :         pfnProgress(1.0, "", pProgressData);
    1080             : 
    1081         114 :     if (eErr != CE_None)
    1082             :     {
    1083          10 :         VSIUnlink(pszFilename);
    1084          10 :         return nullptr;
    1085             :     }
    1086             : 
    1087             :     /* -------------------------------------------------------------------- */
    1088             :     /*      Re-open dataset, and copy any auxiliary pam information.        */
    1089             :     /* -------------------------------------------------------------------- */
    1090         208 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
    1091             : 
    1092             :     /* If writing to stdout, we can't reopen it, so return */
    1093             :     /* a fake dataset to make the caller happy */
    1094         104 :     CPLPushErrorHandler(CPLQuietErrorHandler);
    1095         104 :     auto poDS = WEBPDataset::OpenPAM(&oOpenInfo);
    1096         104 :     CPLPopErrorHandler();
    1097         104 :     if (poDS)
    1098             :     {
    1099         104 :         poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
    1100         104 :         return poDS;
    1101             :     }
    1102             : 
    1103           0 :     return nullptr;
    1104             : }
    1105             : 
    1106             : /************************************************************************/
    1107             : /*                         GDALRegister_WEBP()                          */
    1108             : /************************************************************************/
    1109             : 
    1110          12 : void GDALRegister_WEBP()
    1111             : 
    1112             : {
    1113          12 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
    1114           0 :         return;
    1115             : 
    1116          12 :     GDALDriver *poDriver = new GDALDriver();
    1117          12 :     WEBPDriverSetCommonMetadata(poDriver);
    1118             : 
    1119          12 :     poDriver->pfnOpen = WEBPDataset::Open;
    1120          12 :     poDriver->pfnCreateCopy = WEBPDataset::CreateCopy;
    1121             : 
    1122          12 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1123             : }

Generated by: LCOV version 1.14