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

Generated by: LCOV version 1.14