LCOV - code coverage report
Current view: top level - frmts/kea - keacopy.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 249 271 91.9 %
Date: 2025-10-21 01:37:22 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  keacopy.cpp
       3             :  *
       4             :  *  Created by Pete Bunting on 01/08/2012.
       5             :  *  Copyright 2012 LibKEA. All rights reserved.
       6             :  *
       7             :  *  This file is part of LibKEA.
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  *
      11             :  */
      12             : 
      13             : #include <cmath>
      14             : #include "gdal_priv.h"
      15             : #include "gdal_rat.h"
      16             : 
      17             : #include "keacopy.h"
      18             : 
      19             : // Support functions for CreateCopy()
      20             : 
      21             : // Copies GDAL Band to KEA Band if nOverview == -1
      22             : // Otherwise it is assumed we are writing to the specified overview
      23          90 : static bool KEACopyRasterData(GDALRasterBand *pBand,
      24             :                               kealib::KEAImageIO *pImageIO, int nBand,
      25             :                               int nOverview, int nTotalBands,
      26             :                               GDALProgressFunc pfnProgress, void *pProgressData)
      27             : {
      28             :     // get some info
      29          90 :     kealib::KEADataType eKeaType = pImageIO->getImageBandDataType(nBand);
      30             :     unsigned int nBlockSize;
      31          90 :     if (nOverview == -1)
      32          89 :         nBlockSize = pImageIO->getImageBlockSize(nBand);
      33             :     else
      34           1 :         nBlockSize = pImageIO->getOverviewBlockSize(nBand, nOverview);
      35             : 
      36          90 :     GDALDataType eGDALType = pBand->GetRasterDataType();
      37          90 :     unsigned int nXSize = pBand->GetXSize();
      38          90 :     unsigned int nYSize = pBand->GetYSize();
      39             : 
      40             :     // allocate some space
      41          90 :     const int nPixelSize = GDALGetDataTypeSizeBytes(eGDALType);
      42          90 :     void *pData = VSIMalloc3(nPixelSize, nBlockSize, nBlockSize);
      43          90 :     if (pData == nullptr)
      44             :     {
      45           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to allocate memory");
      46           0 :         return false;
      47             :     }
      48             :     // for progress
      49          90 :     const uint64_t nTotalBlocks =
      50          90 :         static_cast<uint64_t>(DIV_ROUND_UP(nXSize, nBlockSize)) *
      51          90 :         DIV_ROUND_UP(nYSize, nBlockSize);
      52          90 :     uint64_t nBlocksComplete = 0;
      53          90 :     double dLastFraction = -1;
      54             :     // go through the image
      55         181 :     for (unsigned int nY = 0; nY < nYSize; nY += nBlockSize)
      56             :     {
      57             :         // adjust for edge blocks
      58          91 :         unsigned int nysize = nBlockSize;
      59          91 :         unsigned int nytotalsize = nY + nBlockSize;
      60          91 :         if (nytotalsize > nYSize)
      61           1 :             nysize -= (nytotalsize - nYSize);
      62         184 :         for (unsigned int nX = 0; nX < nXSize; nX += nBlockSize)
      63             :         {
      64             :             // adjust for edge blocks
      65          93 :             unsigned int nxsize = nBlockSize;
      66          93 :             unsigned int nxtotalsize = nX + nBlockSize;
      67          93 :             if (nxtotalsize > nXSize)
      68           2 :                 nxsize -= (nxtotalsize - nXSize);
      69             : 
      70             :             // read in from GDAL
      71         186 :             if (pBand->RasterIO(GF_Read, nX, nY, nxsize, nysize, pData, nxsize,
      72             :                                 nysize, eGDALType, nPixelSize,
      73          93 :                                 nPixelSize * nBlockSize, nullptr) != CE_None)
      74             :             {
      75           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
      76             :                          "Unable to read block at %d %d\n", nX, nY);
      77           0 :                 return false;
      78             :             }
      79             :             // write out to KEA
      80          93 :             if (nOverview == -1)
      81          92 :                 pImageIO->writeImageBlock2Band(nBand, pData, nX, nY, nxsize,
      82             :                                                nysize, nBlockSize, nBlockSize,
      83             :                                                eKeaType);
      84             :             else
      85           1 :                 pImageIO->writeToOverview(nBand, nOverview, pData, nX, nY,
      86             :                                           nxsize, nysize, nBlockSize,
      87             :                                           nBlockSize, eKeaType);
      88             : 
      89             :             // progress
      90          93 :             nBlocksComplete++;
      91          93 :             if (nOverview == -1)
      92             :             {
      93          92 :                 double dFraction =
      94          92 :                     (((double)nBlocksComplete / (double)nTotalBlocks) /
      95          92 :                      (double)nTotalBands) +
      96          92 :                     ((double)(nBand - 1) * (1.0 / (double)nTotalBands));
      97          92 :                 if (dFraction != dLastFraction)
      98             :                 {
      99          92 :                     if (!pfnProgress(dFraction, nullptr, pProgressData))
     100             :                     {
     101           0 :                         CPLFree(pData);
     102           0 :                         return false;
     103             :                     }
     104          92 :                     dLastFraction = dFraction;
     105             :                 }
     106             :             }
     107             :         }
     108             :     }
     109             : 
     110          90 :     CPLFree(pData);
     111          90 :     return true;
     112             : }
     113             : 
     114             : // copies the raster attribute table
     115          89 : static void KEACopyRAT(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO,
     116             :                        int nBand)
     117             : {
     118          89 :     const GDALRasterAttributeTable *gdalAtt = pBand->GetDefaultRAT();
     119          89 :     if ((gdalAtt != nullptr) && (gdalAtt->GetRowCount() > 0))
     120             :     {
     121             :         // some operations depend on whether the input dataset is HFA
     122             :         int bInputHFA =
     123           6 :             pBand->GetDataset()->GetDriver() != nullptr &&
     124           3 :             EQUAL(pBand->GetDataset()->GetDriver()->GetDescription(), "HFA");
     125             : 
     126             :         kealib::KEAAttributeTable *keaAtt =
     127           3 :             pImageIO->getAttributeTable(kealib::kea_att_file, nBand);
     128             : 
     129             :         /*bool redDef = false;
     130             :         int redIdx = -1;
     131             :         bool greenDef = false;
     132             :         int greenIdx = -1;
     133             :         bool blueDef = false;
     134             :         int blueIdx = -1;
     135             :         bool alphaDef = false;
     136             :         int alphaIdx = -1;*/
     137             : 
     138           3 :         int numCols = gdalAtt->GetColumnCount();
     139             :         std::vector<kealib::KEAATTField *> *fields =
     140           3 :             new std::vector<kealib::KEAATTField *>();
     141             :         kealib::KEAATTField *field;
     142          21 :         for (int ni = 0; ni < numCols; ++ni)
     143             :         {
     144          18 :             field = new kealib::KEAATTField();
     145          18 :             field->name = gdalAtt->GetNameOfCol(ni);
     146             : 
     147          18 :             field->dataType = kealib::kea_att_string;
     148          18 :             switch (gdalAtt->GetTypeOfCol(ni))
     149             :             {
     150          12 :                 case GFT_Integer:
     151          12 :                     field->dataType = kealib::kea_att_int;
     152          12 :                     break;
     153           2 :                 case GFT_Real:
     154           2 :                     field->dataType = kealib::kea_att_float;
     155           2 :                     break;
     156           3 :                 case GFT_String:
     157           3 :                     field->dataType = kealib::kea_att_string;
     158           3 :                     break;
     159           1 :                 case GFT_Boolean:
     160           1 :                     field->dataType = kealib::kea_att_bool;
     161           1 :                     break;
     162           0 :                 case GFT_DateTime:
     163             :                 case GFT_WKBGeometry:
     164             :                     // leave as "kea_att_string"
     165           0 :                     break;
     166             :             }
     167             : 
     168          18 :             if (bInputHFA && (field->name == "Histogram"))
     169             :             {
     170           0 :                 field->usage = "PixelCount";
     171           0 :                 field->dataType = kealib::kea_att_int;
     172             :             }
     173          18 :             else if (bInputHFA && (field->name == "Opacity"))
     174             :             {
     175           0 :                 field->name = "Alpha";
     176           0 :                 field->usage = "Alpha";
     177           0 :                 field->dataType = kealib::kea_att_int;
     178             :                 /*alphaDef = true;
     179             :                 alphaIdx = ni;*/
     180             :             }
     181             :             else
     182             :             {
     183          18 :                 field->usage = "Generic";
     184          18 :                 switch (gdalAtt->GetUsageOfCol(ni))
     185             :                 {
     186           1 :                     case GFU_PixelCount:
     187           1 :                         field->usage = "PixelCount";
     188           1 :                         break;
     189           1 :                     case GFU_Name:
     190           1 :                         field->usage = "Name";
     191           1 :                         break;
     192           3 :                     case GFU_Red:
     193           3 :                         field->usage = "Red";
     194           3 :                         if (bInputHFA)
     195             :                         {
     196           0 :                             field->dataType = kealib::kea_att_int;
     197             :                             /*redDef = true;
     198             :                             redIdx = ni;*/
     199             :                         }
     200           3 :                         break;
     201           3 :                     case GFU_Green:
     202           3 :                         field->usage = "Green";
     203           3 :                         if (bInputHFA)
     204             :                         {
     205           0 :                             field->dataType = kealib::kea_att_int;
     206             :                             /*greenDef = true;
     207             :                             greenIdx = ni;*/
     208             :                         }
     209           3 :                         break;
     210           3 :                     case GFU_Blue:
     211           3 :                         field->usage = "Blue";
     212           3 :                         if (bInputHFA)
     213             :                         {
     214           0 :                             field->dataType = kealib::kea_att_int;
     215             :                             /*blueDef = true;
     216             :                             blueIdx = ni;*/
     217             :                         }
     218           3 :                         break;
     219           3 :                     case GFU_Alpha:
     220           3 :                         field->usage = "Alpha";
     221           3 :                         break;
     222           4 :                     default:
     223             :                         // leave as "Generic"
     224           4 :                         break;
     225             :                 }
     226             :             }
     227             : 
     228          18 :             fields->push_back(field);
     229             :         }
     230             : 
     231             :         // This function will populate the field indexes used within
     232             :         // the KEA RAT.
     233           3 :         keaAtt->addFields(fields);
     234             : 
     235           3 :         int numRows = gdalAtt->GetRowCount();
     236           3 :         keaAtt->addRows(numRows);
     237             : 
     238           3 :         bool *pbBuffer = nullptr;
     239           3 :         int *pnIntBuffer = nullptr;
     240           3 :         int64_t *pnInt64Buffer = nullptr;
     241           3 :         double *pfDoubleBuffer = nullptr;
     242           6 :         for (int ni = 0; ni < numRows; ni += kealib::KEA_ATT_CHUNK_SIZE)
     243             :         {
     244           3 :             int nLength = kealib::KEA_ATT_CHUNK_SIZE;
     245           3 :             if ((ni + nLength) > numRows)
     246             :             {
     247           3 :                 nLength = numRows - ni;
     248             :             }
     249          21 :             for (int nj = 0; nj < numCols; ++nj)
     250             :             {
     251          18 :                 field = fields->at(nj);
     252             : 
     253          18 :                 switch (field->dataType)
     254             :                 {
     255           1 :                     case kealib::kea_att_bool:
     256           1 :                         if (!pbBuffer)
     257           1 :                             pbBuffer = new bool[kealib::KEA_ATT_CHUNK_SIZE];
     258             :                         ((GDALRasterAttributeTable *)gdalAtt)
     259           1 :                             ->ValuesIO(GF_Read, nj, ni, nLength, pbBuffer);
     260           1 :                         keaAtt->setBoolFields(ni, nLength, field->idx,
     261           1 :                                               pbBuffer);
     262           1 :                         break;
     263          12 :                     case kealib::kea_att_int:
     264          12 :                         if (!pnIntBuffer)
     265           3 :                             pnIntBuffer = new int[kealib::KEA_ATT_CHUNK_SIZE];
     266          12 :                         if (!pnInt64Buffer)
     267             :                             pnInt64Buffer =
     268           3 :                                 new int64_t[kealib::KEA_ATT_CHUNK_SIZE];
     269             :                         ((GDALRasterAttributeTable *)gdalAtt)
     270          12 :                             ->ValuesIO(GF_Read, nj, ni, nLength, pnIntBuffer);
     271          40 :                         for (int i = 0; i < nLength; i++)
     272             :                         {
     273          28 :                             pnInt64Buffer[i] = pnIntBuffer[i];
     274             :                         }
     275          12 :                         keaAtt->setIntFields(ni, nLength, field->idx,
     276          12 :                                              pnInt64Buffer);
     277          12 :                         break;
     278           2 :                     case kealib::kea_att_float:
     279           2 :                         if (!pfDoubleBuffer)
     280             :                             pfDoubleBuffer =
     281           1 :                                 new double[kealib::KEA_ATT_CHUNK_SIZE];
     282             :                         ((GDALRasterAttributeTable *)gdalAtt)
     283           2 :                             ->ValuesIO(GF_Read, nj, ni, nLength,
     284           2 :                                        pfDoubleBuffer);
     285           2 :                         keaAtt->setFloatFields(ni, nLength, field->idx,
     286           2 :                                                pfDoubleBuffer);
     287           2 :                         break;
     288           3 :                     case kealib::kea_att_string:
     289             :                     {
     290             :                         char **papszColData =
     291           3 :                             (char **)VSIMalloc2(nLength, sizeof(char *));
     292             :                         ((GDALRasterAttributeTable *)gdalAtt)
     293           3 :                             ->ValuesIO(GF_Read, nj, ni, nLength, papszColData);
     294             : 
     295           6 :                         std::vector<std::string> aStringBuffer;
     296           6 :                         for (int i = 0; i < nLength; i++)
     297             :                         {
     298           3 :                             aStringBuffer.push_back(papszColData[i]);
     299             :                         }
     300             : 
     301           6 :                         for (int i = 0; i < nLength; i++)
     302           3 :                             CPLFree(papszColData[i]);
     303           3 :                         CPLFree(papszColData);
     304             : 
     305           3 :                         keaAtt->setStringFields(ni, nLength, field->idx,
     306           3 :                                                 &aStringBuffer);
     307             :                     }
     308           3 :                     break;
     309           0 :                     default:
     310             :                         // Ignore as data type is not known or available from a
     311             :                         // HFA/GDAL RAT."
     312           0 :                         break;
     313             :                 }
     314             :             }
     315             :         }
     316             : 
     317           3 :         delete[] pbBuffer;
     318           3 :         delete[] pnIntBuffer;
     319           3 :         delete[] pnInt64Buffer;
     320           3 :         delete[] pfDoubleBuffer;
     321             : 
     322           3 :         delete keaAtt;
     323          18 :         for (std::vector<kealib::KEAATTField *>::iterator iterField =
     324           3 :                  fields->begin();
     325          39 :              iterField != fields->end(); ++iterField)
     326             :         {
     327          18 :             delete *iterField;
     328             :         }
     329           3 :         delete fields;
     330             :     }
     331          89 : }
     332             : 
     333             : // copies the metadata
     334             : // pass nBand == -1 to copy a dataset's metadata
     335             : // or band index to copy a band's metadata
     336         151 : static void KEACopyMetadata(GDALMajorObject *pObject,
     337             :                             kealib::KEAImageIO *pImageIO, int nBand)
     338             : {
     339         151 :     char **ppszMetadata = pObject->GetMetadata();
     340         151 :     if (ppszMetadata != nullptr)
     341             :     {
     342          86 :         int nCount = 0;
     343         252 :         while (ppszMetadata[nCount] != nullptr)
     344             :         {
     345         166 :             char *pszName = nullptr;
     346             :             const char *pszValue =
     347         166 :                 CPLParseNameValue(ppszMetadata[nCount], &pszName);
     348         166 :             if (pszValue == nullptr)
     349          12 :                 pszValue = "";
     350         166 :             if (pszName != nullptr)
     351             :             {
     352             :                 // it is LAYER_TYPE and a Band? if so handle separately
     353         154 :                 if ((nBand != -1) && EQUAL(pszName, "LAYER_TYPE"))
     354             :                 {
     355          55 :                     if (EQUAL(pszValue, "athematic"))
     356             :                     {
     357          53 :                         pImageIO->setImageBandLayerType(nBand,
     358             :                                                         kealib::kea_continuous);
     359             :                     }
     360             :                     else
     361             :                     {
     362           2 :                         pImageIO->setImageBandLayerType(nBand,
     363             :                                                         kealib::kea_thematic);
     364             :                     }
     365             :                 }
     366          99 :                 else if ((nBand != -1) &&
     367          84 :                          EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     368             :                 {
     369             :                     // This gets copied across as part of the attributes
     370             :                     // so ignore for now.
     371             :                 }
     372             :                 else
     373             :                 {
     374             :                     // write it into the image
     375          99 :                     if (nBand != -1)
     376          84 :                         pImageIO->setImageBandMetaData(nBand, pszName,
     377             :                                                        pszValue);
     378             :                     else
     379          15 :                         pImageIO->setImageMetaData(pszName, pszValue);
     380             :                 }
     381         154 :                 CPLFree(pszName);
     382             :             }
     383         166 :             nCount++;
     384             :         }
     385             :     }
     386         151 : }
     387             : 
     388             : // copies the description over
     389          89 : static void KEACopyDescription(GDALRasterBand *pBand,
     390             :                                kealib::KEAImageIO *pImageIO, int nBand)
     391             : {
     392          89 :     const char *pszDesc = pBand->GetDescription();
     393          89 :     pImageIO->setImageBandDescription(nBand, pszDesc);
     394          89 : }
     395             : 
     396             : // copies the no data value across
     397          89 : static void KEACopyNoData(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO,
     398             :                           int nBand)
     399             : {
     400          89 :     int bSuccess = 0;
     401          89 :     double dNoData = pBand->GetNoDataValue(&bSuccess);
     402          89 :     if (bSuccess)
     403             :     {
     404          17 :         pImageIO->setNoDataValue(nBand, &dNoData, kealib::kea_64float);
     405             :     }
     406          89 : }
     407             : 
     408          89 : static bool KEACopyBand(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO,
     409             :                         int nBand, int nTotalbands,
     410             :                         GDALProgressFunc pfnProgress, void *pProgressData)
     411             : {
     412             :     // first copy the raster data over
     413          89 :     if (!KEACopyRasterData(pBand, pImageIO, nBand, -1, nTotalbands, pfnProgress,
     414             :                            pProgressData))
     415           0 :         return false;
     416             : 
     417             :     // are there any overviews?
     418          89 :     int nOverviews = pBand->GetOverviewCount();
     419          90 :     for (int nOverviewCount = 0; nOverviewCount < nOverviews; nOverviewCount++)
     420             :     {
     421           1 :         GDALRasterBand *pOverview = pBand->GetOverview(nOverviewCount);
     422           1 :         int nOverviewXSize = pOverview->GetXSize();
     423           1 :         int nOverviewYSize = pOverview->GetYSize();
     424           1 :         pImageIO->createOverview(nBand, nOverviewCount + 1, nOverviewXSize,
     425             :                                  nOverviewYSize);
     426           1 :         if (!KEACopyRasterData(pOverview, pImageIO, nBand, nOverviewCount + 1,
     427             :                                nTotalbands, pfnProgress, pProgressData))
     428           0 :             return false;
     429             :     }
     430             : 
     431             :     // now metadata
     432          89 :     KEACopyMetadata(pBand, pImageIO, nBand);
     433             : 
     434             :     // and attributes
     435          89 :     KEACopyRAT(pBand, pImageIO, nBand);
     436             : 
     437             :     // and description
     438          89 :     KEACopyDescription(pBand, pImageIO, nBand);
     439             : 
     440             :     // and no data
     441          89 :     KEACopyNoData(pBand, pImageIO, nBand);
     442             : 
     443          89 :     return true;
     444             : }
     445             : 
     446          62 : static void KEACopySpatialInfo(GDALDataset *pDataset,
     447             :                                kealib::KEAImageIO *pImageIO)
     448             : {
     449          62 :     kealib::KEAImageSpatialInfo *pSpatialInfo = pImageIO->getSpatialInfo();
     450             : 
     451          62 :     GDALGeoTransform gt;
     452          62 :     if (pDataset->GetGeoTransform(gt) == CE_None)
     453             :     {
     454             :         // convert back from GDAL's array format
     455          62 :         pSpatialInfo->tlX = gt[0];
     456          62 :         pSpatialInfo->xRes = gt[1];
     457          62 :         pSpatialInfo->xRot = gt[2];
     458          62 :         pSpatialInfo->tlY = gt[3];
     459          62 :         pSpatialInfo->yRot = gt[4];
     460          62 :         pSpatialInfo->yRes = gt[5];
     461             :     }
     462             : 
     463          62 :     const char *pszProjection = pDataset->GetProjectionRef();
     464          62 :     pSpatialInfo->wktString = pszProjection;
     465             : 
     466          62 :     pImageIO->setSpatialInfo(pSpatialInfo);
     467          62 : }
     468             : 
     469             : // copies the GCP's across
     470          62 : static void KEACopyGCPs(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO)
     471             : {
     472          62 :     int nGCPs = pDataset->GetGCPCount();
     473             : 
     474          62 :     if (nGCPs > 0)
     475             :     {
     476           2 :         std::vector<kealib::KEAImageGCP *> KEAGCPs;
     477           1 :         const GDAL_GCP *pGDALGCPs = pDataset->GetGCPs();
     478             : 
     479           3 :         for (int n = 0; n < nGCPs; n++)
     480             :         {
     481           2 :             kealib::KEAImageGCP *pGCP = new kealib::KEAImageGCP;
     482           2 :             pGCP->pszId = pGDALGCPs[n].pszId;
     483           2 :             pGCP->pszInfo = pGDALGCPs[n].pszInfo;
     484           2 :             pGCP->dfGCPPixel = pGDALGCPs[n].dfGCPPixel;
     485           2 :             pGCP->dfGCPLine = pGDALGCPs[n].dfGCPLine;
     486           2 :             pGCP->dfGCPX = pGDALGCPs[n].dfGCPX;
     487           2 :             pGCP->dfGCPY = pGDALGCPs[n].dfGCPY;
     488           2 :             pGCP->dfGCPZ = pGDALGCPs[n].dfGCPZ;
     489           2 :             KEAGCPs.push_back(pGCP);
     490             :         }
     491             : 
     492           1 :         const char *pszGCPProj = pDataset->GetGCPProjection();
     493             :         try
     494             :         {
     495           1 :             pImageIO->setGCPs(&KEAGCPs, pszGCPProj);
     496             :         }
     497           0 :         catch (const kealib::KEAException &)
     498             :         {
     499             :         }
     500             : 
     501           3 :         for (std::vector<kealib::KEAImageGCP *>::iterator itr = KEAGCPs.begin();
     502           5 :              itr != KEAGCPs.end(); ++itr)
     503             :         {
     504           2 :             delete (*itr);
     505             :         }
     506             :     }
     507          62 : }
     508             : 
     509          62 : bool KEACopyFile(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO,
     510             :                  GDALProgressFunc pfnProgress, void *pProgressData)
     511             : {
     512             :     // Main function - copies pDataset to pImageIO
     513             : 
     514             :     // Copy across the spatial info.
     515          62 :     KEACopySpatialInfo(pDataset, pImageIO);
     516             : 
     517             :     // dataset metadata
     518          62 :     KEACopyMetadata(pDataset, pImageIO, -1);
     519             : 
     520             :     // GCPs
     521          62 :     KEACopyGCPs(pDataset, pImageIO);
     522             : 
     523             :     // now copy all the bands over
     524          62 :     int nBands = pDataset->GetRasterCount();
     525         151 :     for (int nBand = 0; nBand < nBands; nBand++)
     526             :     {
     527          89 :         GDALRasterBand *pBand = pDataset->GetRasterBand(nBand + 1);
     528          89 :         if (!KEACopyBand(pBand, pImageIO, nBand + 1, nBands, pfnProgress,
     529             :                          pProgressData))
     530           0 :             return false;
     531             :     }
     532             : 
     533          62 :     pfnProgress(1.0, nullptr, pProgressData);
     534          62 :     return true;
     535             : }

Generated by: LCOV version 1.14