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

Generated by: LCOV version 1.14