LCOV - code coverage report
Current view: top level - gcore - gdal_rat.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 927 1080 85.8 %
Date: 2026-06-03 16:29:47 Functions: 84 98 85.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of GDALRasterAttributeTable and related classes.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2005, Frank Warmerdam
       9             :  * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdal.h"
      16             : #include "gdal_priv.h"
      17             : #include "gdal_rat.h"
      18             : 
      19             : #include <cmath>
      20             : #include <cstddef>
      21             : #include <cstdlib>
      22             : 
      23             : #include <algorithm>
      24             : #include <vector>
      25             : 
      26             : #include "cpl_conv.h"
      27             : #include "cpl_error.h"
      28             : #include "cpl_string.h"
      29             : #include "cpl_vsi.h"
      30             : #include "cpl_vsi_virtual.h"
      31             : 
      32             : #ifdef __clang__
      33             : #pragma clang diagnostic push
      34             : #pragma clang diagnostic ignored "-Wunknown-pragmas"
      35             : #pragma clang diagnostic ignored "-Wdocumentation"
      36             : #pragma clang diagnostic ignored "-Wold-style-cast"
      37             : #endif
      38             : #include "json.h"
      39             : #ifdef __clang__
      40             : #pragma clang diagnostic pop
      41             : #endif
      42             : #include "ogrlibjsonutils.h"
      43             : 
      44             : // NOTE: keep the below description in sync with doc/source/user/raster_data_model.rst::raster_data_model_rat
      45             : 
      46             : /**
      47             :  * \class GDALRasterAttributeTable
      48             :  *
      49             :  * The GDALRasterAttributeTable (or RAT) class is used to encapsulate a table
      50             :  * used to provide attribute information about pixel values.  Each row
      51             :  * in the table applies to a range of pixel values (or a single value in
      52             :  * some cases), and might have attributes such as the histogram count for
      53             :  * that range, the color pixels of that range should be drawn names of classes
      54             :  * or any other generic information.
      55             :  *
      56             :  * Raster attribute tables can be used to represent histograms, color tables,
      57             :  * and classification information.
      58             :  *
      59             :  * Each column in a raster attribute table has a name, a type (integer,
      60             :  * floating point, string, boolean, date time, geometries encoded as WKB),
      61             :  * and a GDALRATFieldUsage.
      62             :  * The usage distinguishes columns with particular understood purposes
      63             :  * (such as color, histogram count, name) and columns that have specific
      64             :  * purposes not understood by the library (long label,
      65             :  * suitability_for_growing_wheat, etc).
      66             :  *
      67             :  * In the general case each row has a column indicating the minimum pixel
      68             :  * values falling into that category, and a column indicating the maximum
      69             :  * pixel value.  These are indicated with usage values of GFU_Min, and
      70             :  * GFU_Max.  In other cases where each row is a discrete pixel value, one
      71             :  * column of usage GFU_MinMax can be used.
      72             :  *
      73             :  * In other cases all the categories are of equal size and regularly spaced
      74             :  * and the categorization information can be determined just by knowing the
      75             :  * value at which the categories start, and the size of a category.  This
      76             :  * is called "Linear Binning" and the information is kept specially on
      77             :  * the raster attribute table as a whole.
      78             :  *
      79             :  * RATs are normally associated with GDALRasterBands and can be queried
      80             :  * using the GDALRasterBand::GetDefaultRAT() method.
      81             :  */
      82             : 
      83             : /************************************************************************/
      84             : /*                      GDALGetRATFieldTypeName()                       */
      85             : /************************************************************************/
      86             : 
      87             : /** Return the string representation of a GDALRATFieldType.
      88             :  *
      89             :  * @since 3.12
      90             :  */
      91          74 : const char *GDALGetRATFieldTypeName(GDALRATFieldType eType)
      92             : {
      93             : #define CASE_GFT(x)                                                            \
      94             :     case GFT_##x:                                                              \
      95             :         return #x
      96             : 
      97          74 :     switch (eType)
      98             :     {
      99          31 :         CASE_GFT(Integer);
     100          11 :         CASE_GFT(String);
     101          12 :         CASE_GFT(Real);
     102           8 :         CASE_GFT(Boolean);
     103           6 :         CASE_GFT(DateTime);
     104           6 :         case GFT_WKBGeometry:
     105           6 :             break;
     106             :     }
     107           6 :     return "WKBGeometry";
     108             : 
     109             : #undef CASE_GFT
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                      GDALGetRATFieldUsageName()                      */
     114             : /************************************************************************/
     115             : 
     116             : /** Return the string representation of a GDALRATFieldUsage.
     117             :  *
     118             :  * @since 3.12
     119             :  */
     120          74 : const char *GDALGetRATFieldUsageName(GDALRATFieldUsage eUsage)
     121             : {
     122             : #define CASE_GFU(x)                                                            \
     123             :     case GFU_##x:                                                              \
     124             :         return #x
     125             : 
     126          74 :     switch (eUsage)
     127             :     {
     128          50 :         CASE_GFU(Generic);
     129           5 :         CASE_GFU(PixelCount);
     130           2 :         CASE_GFU(Name);
     131           0 :         CASE_GFU(Min);
     132           0 :         CASE_GFU(Max);
     133          17 :         CASE_GFU(MinMax);
     134           0 :         CASE_GFU(Red);
     135           0 :         CASE_GFU(Green);
     136           0 :         CASE_GFU(Blue);
     137           0 :         CASE_GFU(Alpha);
     138           0 :         CASE_GFU(RedMin);
     139           0 :         CASE_GFU(GreenMin);
     140           0 :         CASE_GFU(BlueMin);
     141           0 :         CASE_GFU(AlphaMin);
     142           0 :         CASE_GFU(RedMax);
     143           0 :         CASE_GFU(GreenMax);
     144           0 :         CASE_GFU(BlueMax);
     145           0 :         CASE_GFU(AlphaMax);
     146           0 :         case GFU_MaxCount:
     147           0 :             break;
     148             :     }
     149           0 :     return "MaxCount";
     150             : 
     151             : #undef CASE_GFU
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                  ~GDALRasterAttributeTable()                         */
     156             : /*                                                                      */
     157             : /*                      Virtual Destructor                              */
     158             : /************************************************************************/
     159             : 
     160             : GDALRasterAttributeTable::~GDALRasterAttributeTable() = default;
     161             : 
     162             : /************************************************************************/
     163             : /*                              ValuesIO()                              */
     164             : /*                                                                      */
     165             : /*                      Default Implementations                         */
     166             : /************************************************************************/
     167             : 
     168             : /**
     169             :  * \brief Read or Write a block of doubles to/from the Attribute Table.
     170             :  *
     171             :  * This method is the same as the C function GDALRATValuesIOAsDouble().
     172             :  *
     173             :  * @param eRWFlag either GF_Read or GF_Write
     174             :  * @param iField column of the Attribute Table
     175             :  * @param iStartRow start row to start reading/writing (zero based)
     176             :  * @param iLength number of rows to read or write
     177             :  * @param pdfData pointer to array of doubles to read/write. Should be at least
     178             :  *   iLength long.
     179             :  *
     180             :  * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
     181             :  *   rows in table.
     182             :  */
     183             : 
     184           8 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
     185             :                                           int iStartRow, int iLength,
     186             :                                           double *pdfData)
     187             : {
     188           8 :     if ((iStartRow + iLength) > GetRowCount())
     189             :     {
     190           0 :         return CE_Failure;
     191             :     }
     192             : 
     193           8 :     CPLErr eErr = CE_None;
     194           8 :     if (eRWFlag == GF_Read)
     195             :     {
     196          28 :         for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
     197             :         {
     198          22 :             pdfData[iIndex - iStartRow] = GetValueAsDouble(iIndex, iField);
     199             :         }
     200             :     }
     201             :     else
     202             :     {
     203           2 :         for (int iIndex = iStartRow;
     204           4 :              eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
     205             :         {
     206           2 :             eErr = SetValue(iIndex, iField, pdfData[iIndex - iStartRow]);
     207             :         }
     208             :     }
     209           8 :     return eErr;
     210             : }
     211             : 
     212             : /************************************************************************/
     213             : /*                      GDALRATValuesIOAsDouble()                       */
     214             : /************************************************************************/
     215             : 
     216             : /**
     217             :  * \brief Read or Write a block of doubles to/from the Attribute Table.
     218             :  *
     219             :  * This function is the same as the C++ method
     220             :  * GDALRasterAttributeTable::ValuesIO()
     221             :  */
     222          30 : CPLErr CPL_STDCALL GDALRATValuesIOAsDouble(GDALRasterAttributeTableH hRAT,
     223             :                                            GDALRWFlag eRWFlag, int iField,
     224             :                                            int iStartRow, int iLength,
     225             :                                            double *pdfData)
     226             : 
     227             : {
     228          30 :     VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDouble", CE_Failure);
     229             : 
     230          60 :     return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
     231          30 :         eRWFlag, iField, iStartRow, iLength, pdfData);
     232             : }
     233             : 
     234             : /**
     235             :  * \brief Read or Write a block of integers to/from the Attribute Table.
     236             :  *
     237             :  * This method is the same as the C function GDALRATValuesIOAsInteger().
     238             :  *
     239             :  * @param eRWFlag either GF_Read or GF_Write
     240             :  * @param iField column of the Attribute Table
     241             :  * @param iStartRow start row to start reading/writing (zero based)
     242             :  * @param iLength number of rows to read or write
     243             :  * @param pnData pointer to array of ints to read/write. Should be at least
     244             :  *     iLength long.
     245             :  *
     246             :  * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
     247             :  *     rows in table.
     248             :  */
     249             : 
     250          11 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
     251             :                                           int iStartRow, int iLength,
     252             :                                           int *pnData)
     253             : {
     254          11 :     if ((iStartRow + iLength) > GetRowCount())
     255             :     {
     256           1 :         return CE_Failure;
     257             :     }
     258             : 
     259          10 :     CPLErr eErr = CE_None;
     260          10 :     if (eRWFlag == GF_Read)
     261             :     {
     262          52 :         for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
     263             :         {
     264          42 :             pnData[iIndex - iStartRow] = GetValueAsInt(iIndex, iField);
     265             :         }
     266             :     }
     267             :     else
     268             :     {
     269           0 :         for (int iIndex = iStartRow;
     270           0 :              eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
     271             :         {
     272           0 :             eErr = SetValue(iIndex, iField, pnData[iIndex - iStartRow]);
     273             :         }
     274             :     }
     275          10 :     return eErr;
     276             : }
     277             : 
     278             : /************************************************************************/
     279             : /*                      GDALRATValuesIOAsInteger()                      */
     280             : /************************************************************************/
     281             : 
     282             : /**
     283             :  * \brief Read or Write a block of ints to/from the Attribute Table.
     284             :  *
     285             :  * This function is the same as the C++ method
     286             :  * GDALRasterAttributeTable::ValuesIO()
     287             :  */
     288          33 : CPLErr CPL_STDCALL GDALRATValuesIOAsInteger(GDALRasterAttributeTableH hRAT,
     289             :                                             GDALRWFlag eRWFlag, int iField,
     290             :                                             int iStartRow, int iLength,
     291             :                                             int *pnData)
     292             : 
     293             : {
     294          33 :     VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsInteger", CE_Failure);
     295             : 
     296          66 :     return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
     297          33 :         eRWFlag, iField, iStartRow, iLength, pnData);
     298             : }
     299             : 
     300             : /**
     301             :  * \brief Read or Write a block of strings to/from the Attribute Table.
     302             :  *
     303             :  * This method is the same as the C function GDALRATValuesIOAsString().
     304             :  * When reading, papszStrList must be already allocated to the correct size.
     305             :  * The caller is expected to call CPLFree on each read string.
     306             :  *
     307             :  * @param eRWFlag either GF_Read or GF_Write
     308             :  * @param iField column of the Attribute Table
     309             :  * @param iStartRow start row to start reading/writing (zero based)
     310             :  * @param iLength number of rows to read or write
     311             :  * @param papszStrList pointer to array of strings to read/write. Should be at
     312             :  *   least iLength long.
     313             :  *
     314             :  * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
     315             :  *   rows in table.
     316             :  */
     317             : 
     318           6 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
     319             :                                           int iStartRow, int iLength,
     320             :                                           char **papszStrList)
     321             : {
     322           6 :     if ((iStartRow + iLength) > GetRowCount())
     323             :     {
     324           0 :         return CE_Failure;
     325             :     }
     326             : 
     327           6 :     CPLErr eErr = CE_None;
     328           6 :     if (eRWFlag == GF_Read)
     329             :     {
     330          28 :         for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
     331             :         {
     332          44 :             papszStrList[iIndex - iStartRow] =
     333          22 :                 VSIStrdup(GetValueAsString(iIndex, iField));
     334             :         }
     335             :     }
     336             :     else
     337             :     {
     338           0 :         for (int iIndex = iStartRow;
     339           0 :              eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
     340             :         {
     341           0 :             eErr = SetValue(iIndex, iField, papszStrList[iIndex - iStartRow]);
     342             :         }
     343             :     }
     344           6 :     return eErr;
     345             : }
     346             : 
     347             : /************************************************************************/
     348             : /*                      GDALRATValuesIOAsString()                       */
     349             : /************************************************************************/
     350             : 
     351             : /**
     352             :  * \brief Read or Write a block of strings to/from the Attribute Table.
     353             :  *
     354             :  * This function is the same as the C++ method
     355             :  * GDALRasterAttributeTable::ValuesIO()
     356             :  */
     357          30 : CPLErr CPL_STDCALL GDALRATValuesIOAsString(GDALRasterAttributeTableH hRAT,
     358             :                                            GDALRWFlag eRWFlag, int iField,
     359             :                                            int iStartRow, int iLength,
     360             :                                            char **papszStrList)
     361             : 
     362             : {
     363          30 :     VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsString", CE_Failure);
     364             : 
     365          60 :     return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
     366          30 :         eRWFlag, iField, iStartRow, iLength, papszStrList);
     367             : }
     368             : 
     369             : /************************************************************************/
     370             : /*                              ValuesIO()                              */
     371             : /************************************************************************/
     372             : 
     373             : /**
     374             :  * \brief Read or Write a block of booleans to/from the Attribute Table.
     375             :  *
     376             :  * This method is the same as the C function GDALRATValuesIOAsBoolean().
     377             :  *
     378             :  * @param eRWFlag either GF_Read or GF_Write
     379             :  * @param iField column of the Attribute Table
     380             :  * @param iStartRow start row to start reading/writing (zero based)
     381             :  * @param iLength number of rows to read or write
     382             :  * @param pbData pointer to array of booleans to read/write. Should be at least
     383             :  *     iLength long.
     384             :  *
     385             :  * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
     386             :  *     rows in table.
     387             :  * @since 3.12
     388             :  */
     389             : 
     390           5 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
     391             :                                           int iStartRow, int iLength,
     392             :                                           bool *pbData)
     393             : {
     394           5 :     if ((iStartRow + iLength) > GetRowCount())
     395             :     {
     396           0 :         return CE_Failure;
     397             :     }
     398             : 
     399           5 :     CPLErr eErr = CE_None;
     400           5 :     if (eRWFlag == GF_Read)
     401             :     {
     402          24 :         for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
     403             :         {
     404          20 :             pbData[iIndex - iStartRow] = GetValueAsBoolean(iIndex, iField);
     405             :         }
     406             :     }
     407             :     else
     408             :     {
     409           1 :         for (int iIndex = iStartRow;
     410           6 :              eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
     411             :         {
     412           5 :             eErr = SetValue(iIndex, iField, pbData[iIndex - iStartRow]);
     413             :         }
     414             :     }
     415           5 :     return eErr;
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                      GDALRATValuesIOAsBoolean()                      */
     420             : /************************************************************************/
     421             : 
     422             : /**
     423             :  * \brief Read or Write a block of booleans to/from the Attribute Table.
     424             :  *
     425             :  * This function is the same as the C++ method
     426             :  * GDALRasterAttributeTable::ValuesIO()
     427             :  *
     428             :  * @since 3.12
     429             :  */
     430           9 : CPLErr GDALRATValuesIOAsBoolean(GDALRasterAttributeTableH hRAT,
     431             :                                 GDALRWFlag eRWFlag, int iField, int iStartRow,
     432             :                                 int iLength, bool *pbData)
     433             : 
     434             : {
     435           9 :     VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsBoolean", CE_Failure);
     436             : 
     437          18 :     return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
     438           9 :         eRWFlag, iField, iStartRow, iLength, pbData);
     439             : }
     440             : 
     441             : /************************************************************************/
     442             : /*                              ValuesIO()                              */
     443             : /************************************************************************/
     444             : 
     445             : /**
     446             :  * \brief Read or Write a block of DateTime to/from the Attribute Table.
     447             :  *
     448             :  * This method is the same as the C function GDALRATValuesIOAsDateTime().
     449             :  *
     450             :  * @param eRWFlag either GF_Read or GF_Write
     451             :  * @param iField column of the Attribute Table
     452             :  * @param iStartRow start row to start reading/writing (zero based)
     453             :  * @param iLength number of rows to read or write
     454             :  * @param psDateTime pointer to array of DateTime to read/write. Should be at
     455             :  *                   least iLength long.
     456             :  *
     457             :  * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
     458             :  *     rows in table.
     459             :  * @since 3.12
     460             :  */
     461             : 
     462           2 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
     463             :                                           int iStartRow, int iLength,
     464             :                                           GDALRATDateTime *psDateTime)
     465             : {
     466           2 :     if ((iStartRow + iLength) > GetRowCount())
     467             :     {
     468           0 :         return CE_Failure;
     469             :     }
     470             : 
     471           2 :     CPLErr eErr = CE_None;
     472           2 :     if (eRWFlag == GF_Read)
     473             :     {
     474           3 :         for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
     475             :         {
     476           2 :             psDateTime[iIndex - iStartRow] = GetValueAsDateTime(iIndex, iField);
     477             :         }
     478             :     }
     479             :     else
     480             :     {
     481           1 :         for (int iIndex = iStartRow;
     482           3 :              eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
     483             :         {
     484           2 :             eErr = SetValue(iIndex, iField, psDateTime[iIndex - iStartRow]);
     485             :         }
     486             :     }
     487           2 :     return eErr;
     488             : }
     489             : 
     490             : /************************************************************************/
     491             : /*                     GDALRATValuesIOAsDateTime()                      */
     492             : /************************************************************************/
     493             : 
     494             : /**
     495             :  * \brief Read or Write a block of date-times to/from the Attribute Table.
     496             :  *
     497             :  * This function is the same as the C++ method
     498             :  * GDALRasterAttributeTable::ValuesIO()
     499             :  *
     500             :  * @since 3.12
     501             :  */
     502           2 : CPLErr GDALRATValuesIOAsDateTime(GDALRasterAttributeTableH hRAT,
     503             :                                  GDALRWFlag eRWFlag, int iField, int iStartRow,
     504             :                                  int iLength, GDALRATDateTime *psDateTime)
     505             : 
     506             : {
     507           2 :     VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDateTime", CE_Failure);
     508             : 
     509           4 :     return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
     510           2 :         eRWFlag, iField, iStartRow, iLength, psDateTime);
     511             : }
     512             : 
     513             : /************************************************************************/
     514             : /*                              ValuesIO()                              */
     515             : /************************************************************************/
     516             : 
     517             : /**
     518             :  * \brief Read or Write a block of WKB-encoded geometries to/from the Attribute Table.
     519             :  *
     520             :  * When reading, each ppabyWKB[] should be CPLFree'd() after use.
     521             :  *
     522             :  * This method is the same as the C function GDALRATValuesIOAsWKBGeometry().
     523             :  *
     524             :  * @param eRWFlag either GF_Read or GF_Write
     525             :  * @param iField column of the Attribute Table
     526             :  * @param iStartRow start row to start reading/writing (zero based)
     527             :  * @param iLength number of rows to read or write
     528             :  * @param ppabyWKB pointer to array of pointer of WKB-encoded geometries to
     529             :  *                 read/write. Should be at least iLength long.
     530             :  * @param pnWKBSize pointer to array of WKB size.
     531             :  *                  Should be at least iLength long.
     532             :  *
     533             :  * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
     534             :  *     rows in table.
     535             :  * @since 3.12
     536             :  */
     537             : 
     538           2 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
     539             :                                           int iStartRow, int iLength,
     540             :                                           GByte **ppabyWKB, size_t *pnWKBSize)
     541             : {
     542           2 :     if ((iStartRow + iLength) > GetRowCount())
     543             :     {
     544           0 :         return CE_Failure;
     545             :     }
     546             : 
     547           2 :     CPLErr eErr = CE_None;
     548           2 :     if (eRWFlag == GF_Read)
     549             :     {
     550           2 :         for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
     551             :         {
     552           1 :             size_t nSize = 0;
     553           1 :             const GByte *pabyWKB = GetValueAsWKBGeometry(iIndex, iField, nSize);
     554           1 :             pnWKBSize[iIndex - iStartRow] = nSize;
     555           1 :             if (nSize)
     556             :             {
     557           2 :                 ppabyWKB[iIndex - iStartRow] =
     558           1 :                     static_cast<GByte *>(CPLMalloc(nSize));
     559           1 :                 memcpy(ppabyWKB[iIndex - iStartRow], pabyWKB, nSize);
     560             :             }
     561             :             else
     562             :             {
     563           0 :                 ppabyWKB[iIndex - iStartRow] = nullptr;
     564             :             }
     565             :         }
     566             :     }
     567             :     else
     568             :     {
     569           1 :         for (int iIndex = iStartRow;
     570           2 :              eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
     571             :         {
     572           1 :             eErr = SetValue(iIndex, iField, ppabyWKB[iIndex - iStartRow],
     573           1 :                             pnWKBSize[iIndex - iStartRow]);
     574             :         }
     575             :     }
     576           2 :     return eErr;
     577             : }
     578             : 
     579             : /************************************************************************/
     580             : /*                    GDALRATValuesIOAsWKBGeometry()                    */
     581             : /************************************************************************/
     582             : 
     583             : /**
     584             :  * \brief Read or Write a block of WKB-encoded geometries to/from the Attribute Table.
     585             :  *
     586             :  * When reading, each ppabyWKB[] should be CPLFree'd() after use.
     587             :  *
     588             :  * This function is the same as the C++ method
     589             :  * GDALRasterAttributeTable::ValuesIO()
     590             :  *
     591             :  * @since 3.12
     592             :  */
     593           2 : CPLErr GDALRATValuesIOAsWKBGeometry(GDALRasterAttributeTableH hRAT,
     594             :                                     GDALRWFlag eRWFlag, int iField,
     595             :                                     int iStartRow, int iLength,
     596             :                                     GByte **ppabyWKB, size_t *pnWKBSize)
     597             : 
     598             : {
     599           2 :     VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsWKBGeometry", CE_Failure);
     600             : 
     601           4 :     return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
     602           2 :         eRWFlag, iField, iStartRow, iLength, ppabyWKB, pnWKBSize);
     603             : }
     604             : 
     605             : //! @cond Doxygen_Suppress
     606             : 
     607             : /************************************************************************/
     608             : /*                     ValuesIOBooleanFromIntoInt()                     */
     609             : /************************************************************************/
     610             : 
     611           7 : CPLErr GDALRasterAttributeTable::ValuesIOBooleanFromIntoInt(
     612             :     GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, bool *pbData)
     613             : {
     614           7 :     if (eRWFlag == GF_Read)
     615             :     {
     616           6 :         std::vector<int> anData(iLength);
     617             :         CPLErr eErr =
     618           6 :             ValuesIO(eRWFlag, iField, iStartRow, iLength, anData.data());
     619           6 :         if (eErr == CE_None)
     620             :         {
     621           4 :             for (int i = 0; i < iLength; ++i)
     622             :             {
     623           2 :                 pbData[i] = anData[i] != 0;
     624             :             }
     625             :         }
     626           6 :         return eErr;
     627             :     }
     628             :     else
     629             :     {
     630           2 :         std::vector<int> anData;
     631           1 :         anData.reserve(iLength);
     632           2 :         for (int i = 0; i < iLength; ++i)
     633           1 :             anData.push_back(pbData[i]);
     634           1 :         return ValuesIO(eRWFlag, iField, iStartRow, iLength, anData.data());
     635             :     }
     636             : }
     637             : 
     638             : /************************************************************************/
     639             : /*                          DateTimeToString()                          */
     640             : /************************************************************************/
     641             : 
     642             : /* static */
     643             : std::string
     644          24 : GDALRasterAttributeTable::DateTimeToString(const GDALRATDateTime &sDateTime)
     645             : {
     646          24 :     if (!sDateTime.bIsValid)
     647           3 :         return std::string();
     648          42 :     return CPLString().Printf(
     649          21 :         "%04d-%02d-%02dT%02d:%02d:%06.3f%c%02d:%02d", sDateTime.nYear,
     650          21 :         sDateTime.nMonth, sDateTime.nDay, sDateTime.nHour, sDateTime.nMinute,
     651          21 :         static_cast<double>(sDateTime.fSecond),
     652          21 :         sDateTime.bPositiveTimeZone ? '+' : '-', sDateTime.nTimeZoneHour,
     653          21 :         sDateTime.nTimeZoneMinute);
     654             : }
     655             : 
     656             : /************************************************************************/
     657             : /*                          StringToDateTime()                          */
     658             : /************************************************************************/
     659             : 
     660             : /* static */
     661          19 : bool GDALRasterAttributeTable::StringToDateTime(const char *pszStr,
     662             :                                                 GDALRATDateTime &sDateTime)
     663             : {
     664             :     OGRField sField;
     665          19 :     if (OGRParseDate(pszStr, &sField, 0))
     666             :     {
     667          16 :         sDateTime.nYear = sField.Date.Year;
     668          16 :         sDateTime.nMonth = sField.Date.Month;
     669          16 :         sDateTime.nDay = sField.Date.Day;
     670          16 :         sDateTime.nHour = sField.Date.Hour;
     671          16 :         sDateTime.nMinute = sField.Date.Minute;
     672          16 :         sDateTime.fSecond = sField.Date.Second;
     673          16 :         sDateTime.bPositiveTimeZone =
     674          16 :             sField.Date.TZFlag <= 2 ? false : sField.Date.TZFlag >= 100;
     675          32 :         sDateTime.nTimeZoneHour = sField.Date.TZFlag <= 2
     676          16 :                                       ? 0
     677          16 :                                       : std::abs(sField.Date.TZFlag - 100) / 4;
     678          16 :         sDateTime.nTimeZoneMinute =
     679          16 :             sField.Date.TZFlag <= 2
     680          16 :                 ? 0
     681          16 :                 : (std::abs(sField.Date.TZFlag - 100) % 4) * 15;
     682          16 :         sDateTime.bIsValid = true;
     683          16 :         return true;
     684             :     }
     685             :     else
     686             :     {
     687           3 :         sDateTime = GDALRATDateTime();
     688           3 :         return false;
     689             :     }
     690             : }
     691             : 
     692             : /************************************************************************/
     693             : /*                   ValuesIODateTimeFromIntoString()                   */
     694             : /************************************************************************/
     695             : 
     696          12 : CPLErr GDALRasterAttributeTable::ValuesIODateTimeFromIntoString(
     697             :     GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     698             :     GDALRATDateTime *psDateTime)
     699             : {
     700          12 :     if (eRWFlag == GF_Read)
     701             :     {
     702           7 :         std::vector<char *> apszStrList(iLength);
     703             :         CPLErr eErr =
     704           7 :             ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStrList.data());
     705           7 :         if (eErr == CE_None)
     706             :         {
     707           8 :             for (int i = 0; i < iLength; ++i)
     708             :             {
     709           4 :                 StringToDateTime(apszStrList[i], psDateTime[i]);
     710             :             }
     711             :         }
     712          14 :         for (int i = 0; i < iLength; ++i)
     713           7 :             VSIFree(apszStrList[i]);
     714           7 :         return eErr;
     715             :     }
     716             :     else
     717             :     {
     718          10 :         std::vector<std::string> asStr;
     719          10 :         std::vector<char *> apszStr;
     720           5 :         asStr.reserve(iLength);
     721           5 :         apszStr.reserve(iLength);
     722          10 :         for (int i = 0; i < iLength; ++i)
     723             :         {
     724           5 :             asStr.push_back(DateTimeToString(psDateTime[i]));
     725           5 :             apszStr.push_back(asStr.back().data());
     726             :         }
     727           5 :         return ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStr.data());
     728             :     }
     729             : }
     730             : 
     731             : /************************************************************************/
     732             : /*                          WKBGeometryToWKT()                          */
     733             : /************************************************************************/
     734             : 
     735             : /* static */
     736          13 : std::string GDALRasterAttributeTable::WKBGeometryToWKT(const void *pabyWKB,
     737             :                                                        size_t nWKBSize)
     738             : {
     739          13 :     std::string osWKT;
     740          13 :     if (nWKBSize)
     741             :     {
     742           9 :         OGRGeometry *poGeometry = nullptr;
     743           9 :         if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeometry,
     744             :                                               nWKBSize,
     745           9 :                                               wkbVariantIso) == OGRERR_NONE)
     746             :         {
     747           9 :             osWKT = poGeometry->exportToWkt();
     748             :         }
     749           9 :         delete poGeometry;
     750             :     }
     751          13 :     return osWKT;
     752             : }
     753             : 
     754             : /************************************************************************/
     755             : /*                          WKTGeometryToWKB()                          */
     756             : /************************************************************************/
     757             : 
     758             : /* static */
     759             : std::vector<GByte>
     760          19 : GDALRasterAttributeTable::WKTGeometryToWKB(const char *pszWKT)
     761             : {
     762          19 :     std::vector<GByte> abyWKB;
     763          19 :     OGRGeometry *poGeom = nullptr;
     764          19 :     if (pszWKT[0] && OGRGeometryFactory::createFromWkt(pszWKT, nullptr,
     765             :                                                        &poGeom) == OGRERR_NONE)
     766             :     {
     767          16 :         const size_t nWKBSize = poGeom->WkbSize();
     768          16 :         abyWKB.resize(nWKBSize);
     769          16 :         poGeom->exportToWkb(wkbNDR, abyWKB.data(), wkbVariantIso);
     770             :     }
     771          19 :     delete poGeom;
     772          38 :     return abyWKB;
     773             : }
     774             : 
     775             : /************************************************************************/
     776             : /*                 ValuesIOWKBGeometryFromIntoString()                  */
     777             : /************************************************************************/
     778             : 
     779          12 : CPLErr GDALRasterAttributeTable::ValuesIOWKBGeometryFromIntoString(
     780             :     GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     781             :     GByte **ppabyWKB, size_t *pnWKBSize)
     782             : {
     783          12 :     if (eRWFlag == GF_Read)
     784             :     {
     785           7 :         std::vector<char *> apszStrList(iLength);
     786             :         CPLErr eErr =
     787           7 :             ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStrList.data());
     788           7 :         if (eErr == CE_None)
     789             :         {
     790           8 :             for (int i = 0; i < iLength; ++i)
     791             :             {
     792           8 :                 auto abyWKB = WKTGeometryToWKB(apszStrList[i]);
     793           4 :                 if (abyWKB.empty())
     794             :                 {
     795           2 :                     ppabyWKB[i] = nullptr;
     796           2 :                     pnWKBSize[i] = 0;
     797             :                 }
     798             :                 else
     799             :                 {
     800           4 :                     ppabyWKB[i] =
     801           2 :                         static_cast<GByte *>(CPLMalloc(abyWKB.size()));
     802           2 :                     memcpy(ppabyWKB[i], abyWKB.data(), abyWKB.size());
     803           2 :                     pnWKBSize[i] = abyWKB.size();
     804             :                 }
     805             :             }
     806             :         }
     807          14 :         for (int i = 0; i < iLength; ++i)
     808           7 :             VSIFree(apszStrList[i]);
     809           7 :         return eErr;
     810             :     }
     811             :     else
     812             :     {
     813          10 :         std::vector<std::string> asStr;
     814          10 :         std::vector<char *> apszStr;
     815           5 :         asStr.reserve(iLength);
     816           5 :         apszStr.reserve(iLength);
     817          10 :         for (int i = 0; i < iLength; ++i)
     818             :         {
     819           5 :             asStr.push_back(WKBGeometryToWKT(ppabyWKB[i], pnWKBSize[i]));
     820           5 :             apszStr.push_back(asStr.back().data());
     821             :         }
     822           5 :         return ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStr.data());
     823             :     }
     824             : }
     825             : 
     826             : //! @endcond
     827             : 
     828             : /************************************************************************/
     829             : /*                            SetRowCount()                             */
     830             : /************************************************************************/
     831             : 
     832             : /**
     833             :  * \brief Set row count.
     834             :  *
     835             :  * Resizes the table to include the indicated number of rows.  Newly created
     836             :  * rows will be initialized to their default values - "" for strings,
     837             :  * and zero for numeric fields.
     838             :  *
     839             :  * This method is the same as the C function GDALRATSetRowCount().
     840             :  *
     841             :  * @param nNewCount the new number of rows.
     842             :  */
     843             : 
     844           0 : void GDALRasterAttributeTable::SetRowCount(CPL_UNUSED int nNewCount)
     845             : {
     846           0 : }
     847             : 
     848             : /************************************************************************/
     849             : /*                         GDALRATSetRowCount()                         */
     850             : /************************************************************************/
     851             : 
     852             : /**
     853             :  * \brief Set row count.
     854             :  *
     855             :  * This function is the same as the C++ method
     856             :  * GDALRasterAttributeTable::SetRowCount()
     857             :  *
     858             :  * @param hRAT RAT handle.
     859             :  * @param nNewCount the new number of rows.
     860             :  */
     861          40 : void CPL_STDCALL GDALRATSetRowCount(GDALRasterAttributeTableH hRAT,
     862             :                                     int nNewCount)
     863             : 
     864             : {
     865          40 :     VALIDATE_POINTER0(hRAT, "GDALRATSetRowCount");
     866             : 
     867          40 :     GDALRasterAttributeTable::FromHandle(hRAT)->SetRowCount(nNewCount);
     868             : }
     869             : 
     870             : /************************************************************************/
     871             : /*                           GetRowOfValue()                            */
     872             : /************************************************************************/
     873             : 
     874             : /**
     875             :  * \fn GDALRasterAttributeTable::GetRowOfValue(double) const
     876             :  * \brief Get row for pixel value.
     877             :  *
     878             :  * Given a raw pixel value, the raster attribute table is scanned to
     879             :  * determine which row in the table applies to the pixel value.  The
     880             :  * row index is returned.
     881             :  *
     882             :  * This method is the same as the C function GDALRATGetRowOfValue().
     883             :  *
     884             :  * @param dfValue the pixel value.
     885             :  *
     886             :  * @return the row index or -1 if no row is appropriate.
     887             :  */
     888             : 
     889             : /**/
     890             : /**/
     891             : 
     892           0 : int GDALRasterAttributeTable::GetRowOfValue(double /* dfValue */) const
     893             : {
     894           0 :     return -1;
     895             : }
     896             : 
     897             : /************************************************************************/
     898             : /*                        GDALRATGetRowOfValue()                        */
     899             : /************************************************************************/
     900             : 
     901             : /**
     902             :  * \brief Get row for pixel value.
     903             :  *
     904             :  * This function is the same as the C++ method
     905             :  * GDALRasterAttributeTable::GetRowOfValue()
     906             :  */
     907           3 : int CPL_STDCALL GDALRATGetRowOfValue(GDALRasterAttributeTableH hRAT,
     908             :                                      double dfValue)
     909             : 
     910             : {
     911           3 :     VALIDATE_POINTER1(hRAT, "GDALRATGetRowOfValue", 0);
     912             : 
     913           3 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowOfValue(dfValue);
     914             : }
     915             : 
     916             : /************************************************************************/
     917             : /*                           GetRowOfValue()                            */
     918             : /************************************************************************/
     919             : 
     920             : /**
     921             :  * \brief Get row for pixel value.
     922             :  *
     923             :  * Given a raw pixel value, the raster attribute table is scanned to
     924             :  * determine which row in the table applies to the pixel value.  The
     925             :  * row index is returned.
     926             :  *
     927             :  * Int arg for now just converted to double.  Perhaps we will
     928             :  * handle this in a special way some day?
     929             :  *
     930             :  * This method is the same as the C function GDALRATGetRowOfValue().
     931             :  *
     932             :  * @param nValue the pixel value.
     933             :  *
     934             :  * @return the row index or -1 if no row is appropriate.
     935             :  */
     936             : 
     937           0 : int GDALRasterAttributeTable::GetRowOfValue(int nValue) const
     938             : 
     939             : {
     940           0 :     return GetRowOfValue(static_cast<double>(nValue));
     941             : }
     942             : 
     943             : /************************************************************************/
     944             : /*                            CreateColumn()                            */
     945             : /************************************************************************/
     946             : 
     947             : /**
     948             :  * \fn GDALRasterAttributeTable::CreateColumn(const char*, GDALRATFieldType,
     949             :  * GDALRATFieldUsage) \brief Create new column.
     950             :  *
     951             :  * If the table already has rows, all row values for the new column will
     952             :  * be initialized to the default value ("", or zero).  The new column is
     953             :  * always created as the last column, and will be column (field)
     954             :  * "GetColumnCount()-1" after CreateColumn() has completed successfully.
     955             :  *
     956             :  * This method is the same as the C function GDALRATCreateColumn().
     957             :  *
     958             :  * @param pszFieldName the name of the field to create.
     959             :  * @param eFieldType the field type (integer, double or string).
     960             :  * @param eFieldUsage the field usage, GFU_Generic if not known.
     961             :  *
     962             :  * @return CE_None on success or CE_Failure if something goes wrong.
     963             :  */
     964             : 
     965             : /**/
     966             : /**/
     967             : 
     968             : CPLErr
     969           0 : GDALRasterAttributeTable::CreateColumn(const char * /* pszFieldName */,
     970             :                                        GDALRATFieldType /* eFieldType */,
     971             :                                        GDALRATFieldUsage /* eFieldUsage */)
     972             : {
     973           0 :     return CE_Failure;
     974             : }
     975             : 
     976             : /************************************************************************/
     977             : /*                        GDALRATCreateColumn()                         */
     978             : /************************************************************************/
     979             : 
     980             : /**
     981             :  * \brief Create new column.
     982             :  *
     983             :  * This function is the same as the C++ method
     984             :  * GDALRasterAttributeTable::CreateColumn()
     985             :  */
     986         182 : CPLErr CPL_STDCALL GDALRATCreateColumn(GDALRasterAttributeTableH hRAT,
     987             :                                        const char *pszFieldName,
     988             :                                        GDALRATFieldType eFieldType,
     989             :                                        GDALRATFieldUsage eFieldUsage)
     990             : 
     991             : {
     992         182 :     VALIDATE_POINTER1(hRAT, "GDALRATCreateColumn", CE_Failure);
     993             : 
     994         364 :     return GDALRasterAttributeTable::FromHandle(hRAT)->CreateColumn(
     995         182 :         pszFieldName, eFieldType, eFieldUsage);
     996             : }
     997             : 
     998             : /************************************************************************/
     999             : /*                          SetLinearBinning()                          */
    1000             : /************************************************************************/
    1001             : 
    1002             : /**
    1003             :  * \brief Set linear binning information.
    1004             :  *
    1005             :  * For RATs with equal sized categories (in pixel value space) that are
    1006             :  * evenly spaced, this method may be used to associate the linear binning
    1007             :  * information with the table.
    1008             :  *
    1009             :  * This method is the same as the C function GDALRATSetLinearBinning().
    1010             :  *
    1011             :  * @param dfRow0MinIn the lower bound (pixel value) of the first category.
    1012             :  * @param dfBinSizeIn the width of each category (in pixel value units).
    1013             :  *
    1014             :  * @return CE_None on success or CE_Failure on failure.
    1015             :  */
    1016             : 
    1017           0 : CPLErr GDALRasterAttributeTable::SetLinearBinning(CPL_UNUSED double dfRow0MinIn,
    1018             :                                                   CPL_UNUSED double dfBinSizeIn)
    1019             : {
    1020           0 :     return CE_Failure;
    1021             : }
    1022             : 
    1023             : /************************************************************************/
    1024             : /*                      GDALRATSetLinearBinning()                       */
    1025             : /************************************************************************/
    1026             : 
    1027             : /**
    1028             :  * \brief Set linear binning information.
    1029             :  *
    1030             :  * This function is the same as the C++ method
    1031             :  * GDALRasterAttributeTable::SetLinearBinning()
    1032             :  */
    1033           1 : CPLErr CPL_STDCALL GDALRATSetLinearBinning(GDALRasterAttributeTableH hRAT,
    1034             :                                            double dfRow0Min, double dfBinSize)
    1035             : 
    1036             : {
    1037           1 :     VALIDATE_POINTER1(hRAT, "GDALRATSetLinearBinning", CE_Failure);
    1038             : 
    1039           2 :     return GDALRasterAttributeTable::FromHandle(hRAT)->SetLinearBinning(
    1040           1 :         dfRow0Min, dfBinSize);
    1041             : }
    1042             : 
    1043             : /************************************************************************/
    1044             : /*                          GetLinearBinning()                          */
    1045             : /************************************************************************/
    1046             : 
    1047             : /**
    1048             :  * \brief Get linear binning information.
    1049             :  *
    1050             :  * Returns linear binning information if any is associated with the RAT.
    1051             :  *
    1052             :  * This method is the same as the C function GDALRATGetLinearBinning().
    1053             :  *
    1054             :  * @param pdfRow0Min (out) the lower bound (pixel value) of the first category.
    1055             :  * @param pdfBinSize (out) the width of each category (in pixel value units).
    1056             :  *
    1057             :  * @return TRUE if linear binning information exists or FALSE if there is none.
    1058             :  */
    1059             : 
    1060           0 : int GDALRasterAttributeTable::GetLinearBinning(
    1061             :     CPL_UNUSED double *pdfRow0Min, CPL_UNUSED double *pdfBinSize) const
    1062             : {
    1063           0 :     return false;
    1064             : }
    1065             : 
    1066             : /************************************************************************/
    1067             : /*                      GDALRATGetLinearBinning()                       */
    1068             : /************************************************************************/
    1069             : 
    1070             : /**
    1071             :  * \brief Get linear binning information.
    1072             :  *
    1073             :  * This function is the same as the C++ method
    1074             :  * GDALRasterAttributeTable::GetLinearBinning()
    1075             :  */
    1076           1 : int CPL_STDCALL GDALRATGetLinearBinning(GDALRasterAttributeTableH hRAT,
    1077             :                                         double *pdfRow0Min, double *pdfBinSize)
    1078             : 
    1079             : {
    1080           1 :     VALIDATE_POINTER1(hRAT, "GDALRATGetLinearBinning", 0);
    1081             : 
    1082           2 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetLinearBinning(
    1083           1 :         pdfRow0Min, pdfBinSize);
    1084             : }
    1085             : 
    1086             : /************************************************************************/
    1087             : /*                        GDALRATGetTableType()                         */
    1088             : /************************************************************************/
    1089             : 
    1090             : /**
    1091             :  * \brief Get Rat Table Type
    1092             :  *
    1093             :  *
    1094             :  * This function is the same as the C++ method
    1095             :  * GDALRasterAttributeTable::GetTableType()
    1096             :  */
    1097          10 : GDALRATTableType CPL_STDCALL GDALRATGetTableType(GDALRasterAttributeTableH hRAT)
    1098             : {
    1099          10 :     VALIDATE_POINTER1(hRAT, "GDALRATGetTableType", GRTT_THEMATIC);
    1100             : 
    1101          10 :     return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->GetTableType();
    1102             : }
    1103             : 
    1104             : /************************************************************************/
    1105             : /*                        GDALRATSetTableType()                         */
    1106             : /************************************************************************/
    1107             : 
    1108             : /**
    1109             :  * \brief Set RAT Table Type
    1110             :  *
    1111             :  *
    1112             :  * This function is the same as the C++ method
    1113             :  * GDALRasterAttributeTable::SetTableType()
    1114             :  */
    1115           3 : CPLErr CPL_STDCALL GDALRATSetTableType(GDALRasterAttributeTableH hRAT,
    1116             :                                        const GDALRATTableType eInTableType)
    1117             : 
    1118             : {
    1119           3 :     VALIDATE_POINTER1(hRAT, "GDALRATSetTableType", CE_Failure);
    1120             : 
    1121           6 :     return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->SetTableType(
    1122           3 :         eInTableType);
    1123             : }
    1124             : 
    1125             : /************************************************************************/
    1126             : /*                             Serialize()                              */
    1127             : /************************************************************************/
    1128             : 
    1129             : /** Serialize as a XML tree.
    1130             :  * @return XML tree.
    1131             :  */
    1132          33 : CPLXMLNode *GDALRasterAttributeTable::Serialize() const
    1133             : 
    1134             : {
    1135          33 :     if ((GetColumnCount() == 0) && (GetRowCount() == 0))
    1136           2 :         return nullptr;
    1137             : 
    1138             :     CPLXMLNode *psTree =
    1139          31 :         CPLCreateXMLNode(nullptr, CXT_Element, "GDALRasterAttributeTable");
    1140             : 
    1141             :     /* -------------------------------------------------------------------- */
    1142             :     /*      Add attributes with regular binning info if appropriate.        */
    1143             :     /* -------------------------------------------------------------------- */
    1144          31 :     char szValue[128] = {'\0'};
    1145          31 :     double dfRow0Min = 0.0;
    1146          31 :     double dfBinSize = 0.0;
    1147             : 
    1148          31 :     if (GetLinearBinning(&dfRow0Min, &dfBinSize))
    1149             :     {
    1150           4 :         CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfRow0Min);
    1151           4 :         CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "Row0Min"),
    1152             :                          CXT_Text, szValue);
    1153             : 
    1154           4 :         CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfBinSize);
    1155           4 :         CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "BinSize"),
    1156             :                          CXT_Text, szValue);
    1157             :     }
    1158             : 
    1159             :     /* -------------------------------------------------------------------- */
    1160             :     /*      Store table type                                                */
    1161             :     /* -------------------------------------------------------------------- */
    1162          31 :     const GDALRATTableType tableType = GetTableType();
    1163          31 :     if (tableType == GRTT_ATHEMATIC)
    1164             :     {
    1165           3 :         CPLsnprintf(szValue, sizeof(szValue), "athematic");
    1166             :     }
    1167             :     else
    1168             :     {
    1169          28 :         CPLsnprintf(szValue, sizeof(szValue), "thematic");
    1170             :     }
    1171          31 :     CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "tableType"),
    1172             :                      CXT_Text, szValue);
    1173             : 
    1174             :     /* -------------------------------------------------------------------- */
    1175             :     /*      Define each column.                                             */
    1176             :     /* -------------------------------------------------------------------- */
    1177          31 :     const int iColCount = GetColumnCount();
    1178             : 
    1179         105 :     for (int iCol = 0; iCol < iColCount; iCol++)
    1180             :     {
    1181          74 :         CPLXMLNode *psCol = CPLCreateXMLNode(psTree, CXT_Element, "FieldDefn");
    1182             : 
    1183          74 :         snprintf(szValue, sizeof(szValue), "%d", iCol);
    1184          74 :         CPLCreateXMLNode(CPLCreateXMLNode(psCol, CXT_Attribute, "index"),
    1185             :                          CXT_Text, szValue);
    1186             : 
    1187          74 :         CPLCreateXMLElementAndValue(psCol, "Name", GetNameOfCol(iCol));
    1188             : 
    1189          74 :         snprintf(szValue, sizeof(szValue), "%d",
    1190          74 :                  static_cast<int>(GetTypeOfCol(iCol)));
    1191             :         CPLXMLNode *psType =
    1192          74 :             CPLCreateXMLElementAndValue(psCol, "Type", szValue);
    1193          74 :         CPLAddXMLAttributeAndValue(psType, "typeAsString",
    1194          74 :                                    GDALGetRATFieldTypeName(GetTypeOfCol(iCol)));
    1195             : 
    1196          74 :         snprintf(szValue, sizeof(szValue), "%d",
    1197          74 :                  static_cast<int>(GetUsageOfCol(iCol)));
    1198             :         CPLXMLNode *psUsage =
    1199          74 :             CPLCreateXMLElementAndValue(psCol, "Usage", szValue);
    1200          74 :         CPLAddXMLAttributeAndValue(
    1201             :             psUsage, "usageAsString",
    1202          74 :             GDALGetRATFieldUsageName(GetUsageOfCol(iCol)));
    1203             :     }
    1204             : 
    1205             :     /* -------------------------------------------------------------------- */
    1206             :     /*      Write out each row.                                             */
    1207             :     /* -------------------------------------------------------------------- */
    1208          31 :     const int iRowCount = GetRowCount();
    1209          31 :     CPLXMLNode *psTail = nullptr;
    1210          31 :     CPLXMLNode *psRow = nullptr;
    1211             : 
    1212        1044 :     for (int iRow = 0; iRow < iRowCount; iRow++)
    1213             :     {
    1214        1013 :         psRow = CPLCreateXMLNode(nullptr, CXT_Element, "Row");
    1215        1013 :         if (psTail == nullptr)
    1216          27 :             CPLAddXMLChild(psTree, psRow);
    1217             :         else
    1218         986 :             psTail->psNext = psRow;
    1219        1013 :         psTail = psRow;
    1220             : 
    1221        1013 :         snprintf(szValue, sizeof(szValue), "%d", iRow);
    1222        1013 :         CPLCreateXMLNode(CPLCreateXMLNode(psRow, CXT_Attribute, "index"),
    1223             :                          CXT_Text, szValue);
    1224             : 
    1225        2026 :         std::string osStr;
    1226        2082 :         for (int iCol = 0; iCol < iColCount; iCol++)
    1227             :         {
    1228        1069 :             const char *pszValue = szValue;
    1229             : 
    1230        1069 :             switch (GetTypeOfCol(iCol))
    1231             :             {
    1232          36 :                 case GFT_Integer:
    1233          72 :                     snprintf(szValue, sizeof(szValue), "%d",
    1234          36 :                              GetValueAsInt(iRow, iCol));
    1235          36 :                     break;
    1236             : 
    1237         995 :                 case GFT_Real:
    1238         995 :                     CPLsnprintf(szValue, sizeof(szValue), "%.16g",
    1239         995 :                                 GetValueAsDouble(iRow, iCol));
    1240         995 :                     break;
    1241             : 
    1242          14 :                 case GFT_String:
    1243          14 :                     pszValue = GetValueAsString(iRow, iCol);
    1244          14 :                     break;
    1245             : 
    1246          10 :                 case GFT_Boolean:
    1247          10 :                     pszValue = GetValueAsBoolean(iRow, iCol) ? "true" : "false";
    1248          10 :                     break;
    1249             : 
    1250           7 :                 case GFT_DateTime:
    1251           7 :                     osStr = DateTimeToString(GetValueAsDateTime(iRow, iCol));
    1252           7 :                     pszValue = osStr.c_str();
    1253           7 :                     break;
    1254             : 
    1255           7 :                 case GFT_WKBGeometry:
    1256             :                 {
    1257           7 :                     size_t nWKBSize = 0;
    1258             :                     const GByte *pabyWKB =
    1259           7 :                         GetValueAsWKBGeometry(iRow, iCol, nWKBSize);
    1260           7 :                     osStr = WKBGeometryToWKT(pabyWKB, nWKBSize);
    1261           7 :                     pszValue = osStr.c_str();
    1262           7 :                     break;
    1263             :                 }
    1264             :             }
    1265             : 
    1266        1069 :             CPLCreateXMLElementAndValue(psRow, "F", pszValue);
    1267             :         }
    1268             :     }
    1269             : 
    1270          31 :     return psTree;
    1271             : }
    1272             : 
    1273             : /************************************************************************/
    1274             : /*                           SerializeJSON()                            */
    1275             : /************************************************************************/
    1276             : 
    1277             : /** Serialize as a JSON object.
    1278             :  * @return JSON object (of type json_object*)
    1279             :  */
    1280           9 : void *GDALRasterAttributeTable::SerializeJSON() const
    1281             : 
    1282             : {
    1283           9 :     json_object *poRAT = json_object_new_object();
    1284             : 
    1285           9 :     if ((GetColumnCount() == 0) && (GetRowCount() == 0))
    1286           0 :         return poRAT;
    1287             : 
    1288             :     /* -------------------------------------------------------------------- */
    1289             :     /*      Add attributes with regular binning info if appropriate.        */
    1290             :     /* -------------------------------------------------------------------- */
    1291           9 :     double dfRow0Min = 0.0;
    1292           9 :     double dfBinSize = 0.0;
    1293           9 :     json_object *poRow0Min = nullptr;
    1294           9 :     json_object *poBinSize = nullptr;
    1295           9 :     json_object *poTableType = nullptr;
    1296             : 
    1297           9 :     if (GetLinearBinning(&dfRow0Min, &dfBinSize))
    1298             :     {
    1299           2 :         poRow0Min = json_object_new_double_with_precision(dfRow0Min, 16);
    1300           2 :         json_object_object_add(poRAT, "row0Min", poRow0Min);
    1301             : 
    1302           2 :         poBinSize = json_object_new_double_with_precision(dfBinSize, 16);
    1303           2 :         json_object_object_add(poRAT, "binSize", poBinSize);
    1304             :     }
    1305             : 
    1306             :     /* -------------------------------------------------------------------- */
    1307             :     /*      Table Type                                                      */
    1308             :     /* -------------------------------------------------------------------- */
    1309           9 :     const GDALRATTableType tableType = GetTableType();
    1310           9 :     if (tableType == GRTT_ATHEMATIC)
    1311             :     {
    1312           2 :         poTableType = json_object_new_string("athematic");
    1313             :     }
    1314             :     else
    1315             :     {
    1316           7 :         poTableType = json_object_new_string("thematic");
    1317             :     }
    1318           9 :     json_object_object_add(poRAT, "tableType", poTableType);
    1319             : 
    1320             :     /* -------------------------------------------------------------------- */
    1321             :     /*      Define each column.                                             */
    1322             :     /* -------------------------------------------------------------------- */
    1323           9 :     const int iColCount = GetColumnCount();
    1324           9 :     json_object *poFieldDefnArray = json_object_new_array();
    1325             : 
    1326          61 :     for (int iCol = 0; iCol < iColCount; iCol++)
    1327             :     {
    1328          52 :         json_object *const poFieldDefn = json_object_new_object();
    1329             : 
    1330          52 :         json_object *const poColumnIndex = json_object_new_int(iCol);
    1331          52 :         json_object_object_add(poFieldDefn, "index", poColumnIndex);
    1332             : 
    1333          52 :         json_object *const poName = json_object_new_string(GetNameOfCol(iCol));
    1334          52 :         json_object_object_add(poFieldDefn, "name", poName);
    1335             : 
    1336             :         json_object *const poType =
    1337          52 :             json_object_new_int(static_cast<int>(GetTypeOfCol(iCol)));
    1338          52 :         json_object_object_add(poFieldDefn, "type", poType);
    1339             : 
    1340             :         json_object *const poUsage =
    1341          52 :             json_object_new_int(static_cast<int>(GetUsageOfCol(iCol)));
    1342          52 :         json_object_object_add(poFieldDefn, "usage", poUsage);
    1343             : 
    1344          52 :         json_object_array_add(poFieldDefnArray, poFieldDefn);
    1345             :     }
    1346             : 
    1347           9 :     json_object_object_add(poRAT, "fieldDefn", poFieldDefnArray);
    1348             : 
    1349             :     /* -------------------------------------------------------------------- */
    1350             :     /*      Write out each row.                                             */
    1351             :     /* -------------------------------------------------------------------- */
    1352           9 :     const int iRowCount = GetRowCount();
    1353           9 :     json_object *poRowArray = json_object_new_array();
    1354             : 
    1355         941 :     for (int iRow = 0; iRow < iRowCount; iRow++)
    1356             :     {
    1357         932 :         json_object *const poRow = json_object_new_object();
    1358             : 
    1359         932 :         json_object *const poRowIndex = json_object_new_int(iRow);
    1360         932 :         json_object_object_add(poRow, "index", poRowIndex);
    1361             : 
    1362         932 :         json_object *const poFArray = json_object_new_array();
    1363             : 
    1364        4047 :         for (int iCol = 0; iCol < iColCount; iCol++)
    1365             :         {
    1366        3115 :             json_object *poF = nullptr;
    1367        3115 :             switch (GetTypeOfCol(iCol))
    1368             :             {
    1369        2854 :                 case GFT_Integer:
    1370        2854 :                     poF = json_object_new_int(GetValueAsInt(iRow, iCol));
    1371        2854 :                     break;
    1372             : 
    1373         228 :                 case GFT_Real:
    1374         228 :                     poF = json_object_new_double_with_precision(
    1375         228 :                         GetValueAsDouble(iRow, iCol), 16);
    1376         228 :                     break;
    1377             : 
    1378          17 :                 case GFT_String:
    1379          17 :                     poF = json_object_new_string(GetValueAsString(iRow, iCol));
    1380          17 :                     break;
    1381             : 
    1382           6 :                 case GFT_Boolean:
    1383             :                     poF =
    1384           6 :                         json_object_new_boolean(GetValueAsBoolean(iRow, iCol));
    1385           6 :                     break;
    1386             : 
    1387          10 :                 case GFT_DateTime:
    1388             :                 case GFT_WKBGeometry:
    1389             :                 {
    1390          10 :                     const char *pszV = GetValueAsString(iRow, iCol);
    1391          10 :                     if (pszV[0])
    1392           6 :                         poF = json_object_new_string(pszV);
    1393          10 :                     break;
    1394             :                 }
    1395             :             }
    1396             : 
    1397        3115 :             json_object_array_add(poFArray, poF);
    1398             :         }
    1399         932 :         json_object_object_add(poRow, "f", poFArray);
    1400         932 :         json_object_array_add(poRowArray, poRow);
    1401             :     }
    1402           9 :     json_object_object_add(poRAT, "row", poRowArray);
    1403             : 
    1404           9 :     return poRAT;
    1405             : }
    1406             : 
    1407             : /************************************************************************/
    1408             : /*                              XMLInit()                               */
    1409             : /************************************************************************/
    1410             : 
    1411             : /** Deserialize from XML.
    1412             :  * @param psTree XML tree
    1413             :  * @return error code.
    1414             :  */
    1415          36 : CPLErr GDALRasterAttributeTable::XMLInit(const CPLXMLNode *psTree,
    1416             :                                          const char * /*pszVRTPath*/)
    1417             : 
    1418             : {
    1419          36 :     CPLAssert(GetRowCount() == 0 && GetColumnCount() == 0);
    1420             : 
    1421             :     /* -------------------------------------------------------------------- */
    1422             :     /*      Linear binning.                                                 */
    1423             :     /* -------------------------------------------------------------------- */
    1424          43 :     if (CPLGetXMLValue(psTree, "Row0Min", nullptr) &&
    1425           7 :         CPLGetXMLValue(psTree, "BinSize", nullptr))
    1426             :     {
    1427           7 :         SetLinearBinning(CPLAtof(CPLGetXMLValue(psTree, "Row0Min", "")),
    1428           7 :                          CPLAtof(CPLGetXMLValue(psTree, "BinSize", "")));
    1429             :     }
    1430             : 
    1431             :     /* -------------------------------------------------------------------- */
    1432             :     /*      Table Type                                                      */
    1433             :     /* -------------------------------------------------------------------- */
    1434          36 :     if (CPLGetXMLValue(psTree, "tableType", nullptr))
    1435             :     {
    1436          34 :         const char *pszValue = CPLGetXMLValue(psTree, "tableType", "thematic");
    1437          34 :         if (EQUAL(pszValue, "athematic"))
    1438             :         {
    1439           4 :             SetTableType(GRTT_ATHEMATIC);
    1440             :         }
    1441             :         else
    1442             :         {
    1443          30 :             SetTableType(GRTT_THEMATIC);
    1444             :         }
    1445             :     }
    1446             : 
    1447             :     /* -------------------------------------------------------------------- */
    1448             :     /*      Column definitions                                              */
    1449             :     /* -------------------------------------------------------------------- */
    1450             : 
    1451        1994 :     for (CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
    1452        1958 :          psChild = psChild->psNext)
    1453             :     {
    1454        1958 :         if (psChild->eType == CXT_Element &&
    1455        1910 :             EQUAL(psChild->pszValue, "FieldDefn"))
    1456             :         {
    1457          88 :             int nType = atoi(CPLGetXMLValue(psChild, "Type", "1"));
    1458          88 :             if (nType < 0 || nType >= GFT_MaxCount)
    1459             :             {
    1460           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1461             :                          "Invalid RAT field type: %d(%s). Dealing as if it was "
    1462             :                          "String",
    1463             :                          nType,
    1464             :                          CPLGetXMLValue(psChild, "typeAsString", "(unknown)"));
    1465           0 :                 nType = GFT_String;
    1466             :             }
    1467          88 :             int nUsage = atoi(CPLGetXMLValue(psChild, "Usage", "0"));
    1468          88 :             if (nUsage < 0 || nUsage >= GFU_MaxCount)
    1469             :             {
    1470           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1471             :                          "Invalid RAT field usage: %d(%s). Dealing as if it "
    1472             :                          "was Generic",
    1473             :                          nUsage,
    1474             :                          CPLGetXMLValue(psChild, "usageAsString", "(unknown)"));
    1475           0 :                 nUsage = GFU_Generic;
    1476             :             }
    1477          88 :             CreateColumn(CPLGetXMLValue(psChild, "Name", ""),
    1478             :                          static_cast<GDALRATFieldType>(nType),
    1479          88 :                          static_cast<GDALRATFieldUsage>(nUsage));
    1480             :         }
    1481             :     }
    1482             : 
    1483             :     /* -------------------------------------------------------------------- */
    1484             :     /*      Row data.                                                       */
    1485             :     /* -------------------------------------------------------------------- */
    1486        1994 :     for (const CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
    1487        1958 :          psChild = psChild->psNext)
    1488             :     {
    1489        1958 :         if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue, "Row"))
    1490             :         {
    1491        1822 :             const int iRow = atoi(CPLGetXMLValue(psChild, "index", "0"));
    1492        1822 :             int iField = 0;
    1493             : 
    1494        5533 :             for (CPLXMLNode *psF = psChild->psChild; psF != nullptr;
    1495        3711 :                  psF = psF->psNext)
    1496             :             {
    1497        3711 :                 if (psF->eType != CXT_Element || !EQUAL(psF->pszValue, "F"))
    1498        1822 :                     continue;
    1499             : 
    1500        1889 :                 if (psF->psChild != nullptr && psF->psChild->eType == CXT_Text)
    1501        1885 :                     SetValue(iRow, iField++, psF->psChild->pszValue);
    1502             :                 else
    1503           4 :                     SetValue(iRow, iField++, "");
    1504             :             }
    1505             :         }
    1506             :     }
    1507             : 
    1508          36 :     return CE_None;
    1509             : }
    1510             : 
    1511             : /************************************************************************/
    1512             : /*                      InitializeFromColorTable()                      */
    1513             : /************************************************************************/
    1514             : 
    1515             : /**
    1516             :  * \brief Initialize from color table.
    1517             :  *
    1518             :  * This method will setup a whole raster attribute table based on the
    1519             :  * contents of the passed color table.  The Value (GFU_MinMax),
    1520             :  * Red (GFU_Red), Green (GFU_Green), Blue (GFU_Blue), and Alpha (GFU_Alpha)
    1521             :  * fields are created, and a row is set for each entry in the color table.
    1522             :  *
    1523             :  * The raster attribute table must be empty before calling
    1524             :  * InitializeFromColorTable().
    1525             :  *
    1526             :  * The Value fields are set based on the implicit assumption with color
    1527             :  * tables that entry 0 applies to pixel value 0, 1 to 1, etc.
    1528             :  *
    1529             :  * This method is the same as the C function GDALRATInitializeFromColorTable().
    1530             :  *
    1531             :  * @param poTable the color table to copy from.
    1532             :  *
    1533             :  * @return CE_None on success or CE_Failure if something goes wrong.
    1534             :  */
    1535             : 
    1536           0 : CPLErr GDALRasterAttributeTable::InitializeFromColorTable(
    1537             :     const GDALColorTable *poTable)
    1538             : 
    1539             : {
    1540           0 :     if (GetRowCount() > 0 || GetColumnCount() > 0)
    1541             :     {
    1542           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1543             :                  "Raster Attribute Table not empty in "
    1544             :                  "InitializeFromColorTable()");
    1545           0 :         return CE_Failure;
    1546             :     }
    1547             : 
    1548           0 :     SetLinearBinning(0.0, 1.0);
    1549           0 :     CreateColumn("Value", GFT_Integer, GFU_MinMax);
    1550           0 :     CreateColumn("Red", GFT_Integer, GFU_Red);
    1551           0 :     CreateColumn("Green", GFT_Integer, GFU_Green);
    1552           0 :     CreateColumn("Blue", GFT_Integer, GFU_Blue);
    1553           0 :     CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
    1554             : 
    1555           0 :     SetRowCount(poTable->GetColorEntryCount());
    1556             : 
    1557           0 :     for (int iRow = 0; iRow < poTable->GetColorEntryCount(); iRow++)
    1558             :     {
    1559             :         GDALColorEntry sEntry;
    1560             : 
    1561           0 :         poTable->GetColorEntryAsRGB(iRow, &sEntry);
    1562             : 
    1563           0 :         SetValue(iRow, 0, iRow);
    1564           0 :         SetValue(iRow, 1, sEntry.c1);
    1565           0 :         SetValue(iRow, 2, sEntry.c2);
    1566           0 :         SetValue(iRow, 3, sEntry.c3);
    1567           0 :         SetValue(iRow, 4, sEntry.c4);
    1568             :     }
    1569             : 
    1570           0 :     return CE_None;
    1571             : }
    1572             : 
    1573             : /************************************************************************/
    1574             : /*                  GDALRATInitializeFromColorTable()                   */
    1575             : /************************************************************************/
    1576             : 
    1577             : /**
    1578             :  * \brief Initialize from color table.
    1579             :  *
    1580             :  * This function is the same as the C++ method
    1581             :  * GDALRasterAttributeTable::InitializeFromColorTable()
    1582             :  */
    1583           0 : CPLErr CPL_STDCALL GDALRATInitializeFromColorTable(
    1584             :     GDALRasterAttributeTableH hRAT, GDALColorTableH hCT)
    1585             : 
    1586             : {
    1587           0 :     VALIDATE_POINTER1(hRAT, "GDALRATInitializeFromColorTable", CE_Failure);
    1588             : 
    1589           0 :     return GDALRasterAttributeTable::FromHandle(hRAT)->InitializeFromColorTable(
    1590           0 :         GDALColorTable::FromHandle(hCT));
    1591             : }
    1592             : 
    1593             : /************************************************************************/
    1594             : /*                       TranslateToColorTable()                        */
    1595             : /************************************************************************/
    1596             : 
    1597             : /**
    1598             :  * \brief Translate to a color table.
    1599             :  *
    1600             :  * This method will attempt to create a corresponding GDALColorTable from
    1601             :  * this raster attribute table.
    1602             :  *
    1603             :  * This method is the same as the C function GDALRATTranslateToColorTable().
    1604             :  *
    1605             :  * @param nEntryCount The number of entries to produce (0 to nEntryCount-1),
    1606             :  * or -1 to auto-determine the number of entries.
    1607             :  *
    1608             :  * @return the generated color table or NULL on failure.
    1609             :  */
    1610             : 
    1611           0 : GDALColorTable *GDALRasterAttributeTable::TranslateToColorTable(int nEntryCount)
    1612             : 
    1613             : {
    1614             :     /* -------------------------------------------------------------------- */
    1615             :     /*      Establish which fields are red, green, blue and alpha.          */
    1616             :     /* -------------------------------------------------------------------- */
    1617           0 :     const int iRed = GetColOfUsage(GFU_Red);
    1618           0 :     const int iGreen = GetColOfUsage(GFU_Green);
    1619           0 :     const int iBlue = GetColOfUsage(GFU_Blue);
    1620             : 
    1621           0 :     if (iRed == -1 || iGreen == -1 || iBlue == -1)
    1622           0 :         return nullptr;
    1623             : 
    1624           0 :     const int iAlpha = GetColOfUsage(GFU_Alpha);
    1625             : 
    1626             :     /* -------------------------------------------------------------------- */
    1627             :     /*      If we aren't given an explicit number of values to scan for,    */
    1628             :     /*      search for the maximum "max" value.                             */
    1629             :     /* -------------------------------------------------------------------- */
    1630           0 :     if (nEntryCount == -1)
    1631             :     {
    1632           0 :         int iMaxCol = GetColOfUsage(GFU_Max);
    1633           0 :         if (iMaxCol == -1)
    1634           0 :             iMaxCol = GetColOfUsage(GFU_MinMax);
    1635             : 
    1636           0 :         if (iMaxCol == -1 || GetRowCount() == 0)
    1637           0 :             return nullptr;
    1638             : 
    1639           0 :         for (int iRow = 0; iRow < GetRowCount(); iRow++)
    1640             :         {
    1641           0 :             nEntryCount = std::max(
    1642           0 :                 nEntryCount, std::min(65535, GetValueAsInt(iRow, iMaxCol)) + 1);
    1643             :         }
    1644             : 
    1645           0 :         if (nEntryCount < 0)
    1646           0 :             return nullptr;
    1647             : 
    1648             :         // Restrict our number of entries to something vaguely sensible.
    1649           0 :         nEntryCount = std::min(65535, nEntryCount);
    1650             :     }
    1651             : 
    1652             :     /* -------------------------------------------------------------------- */
    1653             :     /*      Assign values to color table.                                   */
    1654             :     /* -------------------------------------------------------------------- */
    1655           0 :     GDALColorTable *poCT = new GDALColorTable();
    1656             : 
    1657           0 :     for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
    1658             :     {
    1659           0 :         GDALColorEntry sColor = {0, 0, 0, 0};
    1660           0 :         const int iRow = GetRowOfValue(iEntry);
    1661             : 
    1662           0 :         if (iRow != -1)
    1663             :         {
    1664           0 :             sColor.c1 = static_cast<short>(GetValueAsInt(iRow, iRed));
    1665           0 :             sColor.c2 = static_cast<short>(GetValueAsInt(iRow, iGreen));
    1666           0 :             sColor.c3 = static_cast<short>(GetValueAsInt(iRow, iBlue));
    1667           0 :             if (iAlpha == -1)
    1668           0 :                 sColor.c4 = 255;
    1669             :             else
    1670           0 :                 sColor.c4 = static_cast<short>(GetValueAsInt(iRow, iAlpha));
    1671             :         }
    1672             : 
    1673           0 :         poCT->SetColorEntry(iEntry, &sColor);
    1674             :     }
    1675             : 
    1676           0 :     return poCT;
    1677             : }
    1678             : 
    1679             : /************************************************************************/
    1680             : /*                  GDALRATInitializeFromColorTable()                   */
    1681             : /************************************************************************/
    1682             : 
    1683             : /**
    1684             :  * \brief Translate to a color table.
    1685             :  *
    1686             :  * This function is the same as the C++ method
    1687             :  * GDALRasterAttributeTable::TranslateToColorTable()
    1688             :  */
    1689             : GDALColorTableH CPL_STDCALL
    1690           0 : GDALRATTranslateToColorTable(GDALRasterAttributeTableH hRAT, int nEntryCount)
    1691             : 
    1692             : {
    1693           0 :     VALIDATE_POINTER1(hRAT, "GDALRATTranslateToColorTable", nullptr);
    1694             : 
    1695           0 :     return GDALRasterAttributeTable::FromHandle(hRAT)->TranslateToColorTable(
    1696           0 :         nEntryCount);
    1697             : }
    1698             : 
    1699             : /************************************************************************/
    1700             : /*                            DumpReadable()                            */
    1701             : /************************************************************************/
    1702             : 
    1703             : /**
    1704             :  * \brief Dump RAT in readable form.
    1705             :  *
    1706             :  * Currently the readable form is the XML encoding ... only barely
    1707             :  * readable.
    1708             :  *
    1709             :  * This method is the same as the C function GDALRATDumpReadable().
    1710             :  *
    1711             :  * @param fp file to dump to or NULL for stdout.
    1712             :  */
    1713             : 
    1714           0 : void GDALRasterAttributeTable::DumpReadable(FILE *fp)
    1715             : 
    1716             : {
    1717           0 :     CPLXMLNode *psTree = Serialize();
    1718           0 :     char *const pszXMLText = CPLSerializeXMLTree(psTree);
    1719             : 
    1720           0 :     CPLDestroyXMLNode(psTree);
    1721             : 
    1722           0 :     if (fp == nullptr)
    1723           0 :         fp = stdout;
    1724             : 
    1725           0 :     fprintf(fp, "%s\n", pszXMLText);
    1726             : 
    1727           0 :     CPLFree(pszXMLText);
    1728           0 : }
    1729             : 
    1730             : /************************************************************************/
    1731             : /*                        GDALRATDumpReadable()                         */
    1732             : /************************************************************************/
    1733             : 
    1734             : /**
    1735             :  * \brief Dump RAT in readable form.
    1736             :  *
    1737             :  * This function is the same as the C++ method
    1738             :  * GDALRasterAttributeTable::DumpReadable()
    1739             :  */
    1740           0 : void CPL_STDCALL GDALRATDumpReadable(GDALRasterAttributeTableH hRAT, FILE *fp)
    1741             : 
    1742             : {
    1743           0 :     VALIDATE_POINTER0(hRAT, "GDALRATDumpReadable");
    1744             : 
    1745           0 :     GDALRasterAttributeTable::FromHandle(hRAT)->DumpReadable(fp);
    1746             : }
    1747             : 
    1748             : /* \class GDALDefaultRasterAttributeTable
    1749             :  *
    1750             :  * An implementation of GDALRasterAttributeTable that keeps
    1751             :  * all data in memory. This is the same as the implementation
    1752             :  * of GDALRasterAttributeTable in GDAL <= 1.10.
    1753             :  */
    1754             : 
    1755             : /************************************************************************/
    1756             : /*                  GDALDefaultRasterAttributeTable()                   */
    1757             : /*                                                                      */
    1758             : /*      Simple initialization constructor.                              */
    1759             : /************************************************************************/
    1760             : 
    1761             : //! Construct empty table.
    1762             : 
    1763             : GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable() = default;
    1764             : 
    1765             : /************************************************************************/
    1766             : /*                   GDALCreateRasterAttributeTable()                   */
    1767             : /************************************************************************/
    1768             : 
    1769             : /**
    1770             :  * \brief Construct empty table.
    1771             :  *
    1772             :  * This function is the same as the C++ method
    1773             :  * GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable()
    1774             :  */
    1775          65 : GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
    1776             : 
    1777             : {
    1778          65 :     return new GDALDefaultRasterAttributeTable();
    1779             : }
    1780             : 
    1781             : /************************************************************************/
    1782             : /*                 ~GDALDefaultRasterAttributeTable()                   */
    1783             : /*                                                                      */
    1784             : /*      All magic done by magic by the container destructors.           */
    1785             : /************************************************************************/
    1786             : 
    1787             : GDALDefaultRasterAttributeTable::~GDALDefaultRasterAttributeTable() = default;
    1788             : 
    1789             : /************************************************************************/
    1790             : /*                  GDALDestroyRasterAttributeTable()                   */
    1791             : /************************************************************************/
    1792             : 
    1793             : /**
    1794             :  * \brief Destroys a RAT.
    1795             :  *
    1796             :  * This function is the same as the C++ method
    1797             :  * GDALRasterAttributeTable::~GDALRasterAttributeTable()
    1798             :  */
    1799          73 : void CPL_STDCALL GDALDestroyRasterAttributeTable(GDALRasterAttributeTableH hRAT)
    1800             : 
    1801             : {
    1802          73 :     if (hRAT != nullptr)
    1803          73 :         delete GDALRasterAttributeTable::FromHandle(hRAT);
    1804          73 : }
    1805             : 
    1806             : /************************************************************************/
    1807             : /*                           AnalyseColumns()                           */
    1808             : /*                                                                      */
    1809             : /*      Internal method to work out which column to use for various     */
    1810             : /*      tasks.                                                          */
    1811             : /************************************************************************/
    1812             : 
    1813           2 : void GDALDefaultRasterAttributeTable::AnalyseColumns()
    1814             : 
    1815             : {
    1816           2 :     bColumnsAnalysed = true;
    1817             : 
    1818           2 :     nMinCol = GetColOfUsage(GFU_Min);
    1819           2 :     if (nMinCol == -1)
    1820           2 :         nMinCol = GetColOfUsage(GFU_MinMax);
    1821             : 
    1822           2 :     nMaxCol = GetColOfUsage(GFU_Max);
    1823           2 :     if (nMaxCol == -1)
    1824           2 :         nMaxCol = GetColOfUsage(GFU_MinMax);
    1825           2 : }
    1826             : 
    1827             : /************************************************************************/
    1828             : /*                           GetColumnCount()                           */
    1829             : /************************************************************************/
    1830             : 
    1831         388 : int GDALDefaultRasterAttributeTable::GetColumnCount() const
    1832             : 
    1833             : {
    1834         388 :     return static_cast<int>(aoFields.size());
    1835             : }
    1836             : 
    1837             : /************************************************************************/
    1838             : /*                       GDALRATGetColumnCount()                        */
    1839             : /************************************************************************/
    1840             : 
    1841             : /**
    1842             :  * \brief Fetch table column count.
    1843             :  *
    1844             :  * This function is the same as the C++ method
    1845             :  * GDALRasterAttributeTable::GetColumnCount()
    1846             :  */
    1847          59 : int CPL_STDCALL GDALRATGetColumnCount(GDALRasterAttributeTableH hRAT)
    1848             : 
    1849             : {
    1850          59 :     VALIDATE_POINTER1(hRAT, "GDALRATGetColumnCount", 0);
    1851             : 
    1852          59 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetColumnCount();
    1853             : }
    1854             : 
    1855             : /************************************************************************/
    1856             : /*                            GetNameOfCol()                            */
    1857             : /************************************************************************/
    1858             : 
    1859             : /** \brief Fetch name of indicated column.
    1860             :  * @param iCol column index.
    1861             :  * @return name.
    1862             :  */
    1863         462 : const char *GDALDefaultRasterAttributeTable::GetNameOfCol(int iCol) const
    1864             : 
    1865             : {
    1866         462 :     if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
    1867           0 :         return "";
    1868             : 
    1869         462 :     return aoFields[iCol].sName;
    1870             : }
    1871             : 
    1872             : /************************************************************************/
    1873             : /*                        GDALRATGetNameOfCol()                         */
    1874             : /************************************************************************/
    1875             : 
    1876             : /**
    1877             :  * \brief Fetch name of indicated column.
    1878             :  *
    1879             :  * This function is the same as the C++ method
    1880             :  * GDALRasterAttributeTable::GetNameOfCol()
    1881             :  * @param hRAT RAT handle.
    1882             :  * @param iCol column index.
    1883             :  * @return name.
    1884             :  */
    1885         192 : const char *CPL_STDCALL GDALRATGetNameOfCol(GDALRasterAttributeTableH hRAT,
    1886             :                                             int iCol)
    1887             : 
    1888             : {
    1889         192 :     VALIDATE_POINTER1(hRAT, "GDALRATGetNameOfCol", nullptr);
    1890             : 
    1891         192 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetNameOfCol(iCol);
    1892             : }
    1893             : 
    1894             : /************************************************************************/
    1895             : /*                           GetUsageOfCol()                            */
    1896             : /************************************************************************/
    1897             : 
    1898             : /**
    1899             :  * \brief Fetch column usage value.
    1900             :  *
    1901             :  * @param iCol column index.
    1902             :  * @return usage.
    1903             :  */
    1904         231 : GDALRATFieldUsage GDALDefaultRasterAttributeTable::GetUsageOfCol(int iCol) const
    1905             : 
    1906             : {
    1907         231 :     if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
    1908           0 :         return GFU_Generic;
    1909             : 
    1910         231 :     return aoFields[iCol].eUsage;
    1911             : }
    1912             : 
    1913             : /************************************************************************/
    1914             : /*                        GDALRATGetUsageOfCol()                        */
    1915             : /************************************************************************/
    1916             : 
    1917             : /**
    1918             :  * \brief Fetch column usage value.
    1919             :  *
    1920             :  * This function is the same as the C++ method
    1921             :  * GDALRasterAttributeTable::GetUsageOfCol()
    1922             :  * @param hRAT RAT handle.
    1923             :  * @param iCol column index.
    1924             :  * @return usage.
    1925             :  */
    1926             : GDALRATFieldUsage CPL_STDCALL
    1927          67 : GDALRATGetUsageOfCol(GDALRasterAttributeTableH hRAT, int iCol)
    1928             : 
    1929             : {
    1930          67 :     VALIDATE_POINTER1(hRAT, "GDALRATGetUsageOfCol", GFU_Generic);
    1931             : 
    1932          67 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetUsageOfCol(iCol);
    1933             : }
    1934             : 
    1935             : /************************************************************************/
    1936             : /*                            GetTypeOfCol()                            */
    1937             : /************************************************************************/
    1938             : 
    1939             : /**
    1940             :  * \brief Fetch column type.
    1941             :  *
    1942             :  * @param iCol column index.
    1943             :  * @return type.
    1944             :  */
    1945        4893 : GDALRATFieldType GDALDefaultRasterAttributeTable::GetTypeOfCol(int iCol) const
    1946             : 
    1947             : {
    1948        4893 :     if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
    1949         665 :         return GFT_Integer;
    1950             : 
    1951        4228 :     return aoFields[iCol].eType;
    1952             : }
    1953             : 
    1954             : /************************************************************************/
    1955             : /*                        GDALRATGetTypeOfCol()                         */
    1956             : /************************************************************************/
    1957             : 
    1958             : /**
    1959             :  * \brief Fetch column type.
    1960             :  *
    1961             :  * This function is the same as the C++ method
    1962             :  * GDALRasterAttributeTable::GetTypeOfCol()
    1963             :  * @param hRAT RAT handle.
    1964             :  * @param iCol column index.
    1965             :  * @return type.
    1966             :  */
    1967         325 : GDALRATFieldType CPL_STDCALL GDALRATGetTypeOfCol(GDALRasterAttributeTableH hRAT,
    1968             :                                                  int iCol)
    1969             : 
    1970             : {
    1971         325 :     VALIDATE_POINTER1(hRAT, "GDALRATGetTypeOfCol", GFT_Integer);
    1972             : 
    1973         325 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetTypeOfCol(iCol);
    1974             : }
    1975             : 
    1976             : /************************************************************************/
    1977             : /*                           GetColOfUsage()                            */
    1978             : /************************************************************************/
    1979             : 
    1980             : /** Return the index of the column that corresponds to the passed usage.
    1981             :  * @param eUsage usage.
    1982             :  * @return column index, or -1 in case of error.
    1983             :  */
    1984          65 : int GDALDefaultRasterAttributeTable::GetColOfUsage(
    1985             :     GDALRATFieldUsage eUsage) const
    1986             : 
    1987             : {
    1988         192 :     for (unsigned int i = 0; i < aoFields.size(); i++)
    1989             :     {
    1990         160 :         if (aoFields[i].eUsage == eUsage)
    1991          33 :             return i;
    1992             :     }
    1993             : 
    1994          32 :     return -1;
    1995             : }
    1996             : 
    1997             : /************************************************************************/
    1998             : /*                        GDALRATGetColOfUsage()                        */
    1999             : /************************************************************************/
    2000             : 
    2001             : /**
    2002             :  * \brief Fetch column index for given usage.
    2003             :  *
    2004             :  * This function is the same as the C++ method
    2005             :  * GDALRasterAttributeTable::GetColOfUsage()
    2006             :  */
    2007          13 : int CPL_STDCALL GDALRATGetColOfUsage(GDALRasterAttributeTableH hRAT,
    2008             :                                      GDALRATFieldUsage eUsage)
    2009             : 
    2010             : {
    2011          13 :     VALIDATE_POINTER1(hRAT, "GDALRATGetColOfUsage", 0);
    2012             : 
    2013          13 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetColOfUsage(eUsage);
    2014             : }
    2015             : 
    2016             : /************************************************************************/
    2017             : /*                            GetRowCount()                             */
    2018             : /************************************************************************/
    2019             : 
    2020        1071 : int GDALDefaultRasterAttributeTable::GetRowCount() const
    2021             : 
    2022             : {
    2023        1071 :     return static_cast<int>(nRowCount);
    2024             : }
    2025             : 
    2026             : /************************************************************************/
    2027             : /*                        GDALRATGetUsageOfCol()                        */
    2028             : /************************************************************************/
    2029             : /**
    2030             :  * \brief Fetch row count.
    2031             :  *
    2032             :  * This function is the same as the C++ method
    2033             :  * GDALRasterAttributeTable::GetRowCount()
    2034             :  */
    2035         270 : int CPL_STDCALL GDALRATGetRowCount(GDALRasterAttributeTableH hRAT)
    2036             : 
    2037             : {
    2038         270 :     VALIDATE_POINTER1(hRAT, "GDALRATGetRowCount", 0);
    2039             : 
    2040         270 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowCount();
    2041             : }
    2042             : 
    2043             : /************************************************************************/
    2044             : /*                          GetValueAsString()                          */
    2045             : /************************************************************************/
    2046             : 
    2047        1304 : const char *GDALDefaultRasterAttributeTable::GetValueAsString(int iRow,
    2048             :                                                               int iField) const
    2049             : 
    2050             : {
    2051        1304 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2052             :     {
    2053           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2054             :                  iField);
    2055             : 
    2056           1 :         return "";
    2057             :     }
    2058             : 
    2059        1303 :     if (iRow < 0 || iRow >= nRowCount)
    2060             :     {
    2061           3 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2062             : 
    2063           3 :         return "";
    2064             :     }
    2065             : 
    2066        1300 :     switch (aoFields[iField].eType)
    2067             :     {
    2068         421 :         case GFT_Integer:
    2069             :         {
    2070             :             const_cast<GDALDefaultRasterAttributeTable *>(this)
    2071         421 :                 ->osWorkingResult.Printf("%d", aoFields[iField].anValues[iRow]);
    2072         421 :             return osWorkingResult;
    2073             :         }
    2074             : 
    2075         289 :         case GFT_Real:
    2076             :         {
    2077             :             const_cast<GDALDefaultRasterAttributeTable *>(this)
    2078             :                 ->osWorkingResult.Printf("%.16g",
    2079         289 :                                          aoFields[iField].adfValues[iRow]);
    2080         289 :             return osWorkingResult;
    2081             :         }
    2082             : 
    2083         567 :         case GFT_String:
    2084             :         {
    2085         567 :             return aoFields[iField].aosValues[iRow];
    2086             :         }
    2087             : 
    2088           2 :         case GFT_Boolean:
    2089             :         {
    2090           2 :             return aoFields[iField].abValues[iRow] ? "true" : "false";
    2091             :         }
    2092             : 
    2093          11 :         case GFT_DateTime:
    2094             :         {
    2095          11 :             const auto &sDateTime = aoFields[iField].asDateTimeValues[iRow];
    2096             :             const_cast<GDALDefaultRasterAttributeTable *>(this)
    2097          11 :                 ->osWorkingResult = DateTimeToString(sDateTime);
    2098          11 :             return osWorkingResult;
    2099             :         }
    2100             : 
    2101          10 :         case GFT_WKBGeometry:
    2102             :         {
    2103          10 :             OGRGeometry *poGeom = nullptr;
    2104          18 :             if (!aoFields[iField].aabyWKBGeometryValues[iRow].empty() &&
    2105          16 :                 OGRGeometryFactory::createFromWkb(
    2106           8 :                     aoFields[iField].aabyWKBGeometryValues[iRow].data(),
    2107             :                     nullptr, &poGeom,
    2108           8 :                     aoFields[iField].aabyWKBGeometryValues[iRow].size(),
    2109             :                     wkbVariantIso) == OGRERR_NONE)
    2110             :             {
    2111             :                 const_cast<GDALDefaultRasterAttributeTable *>(this)
    2112           8 :                     ->osWorkingResult = poGeom->exportToWkt();
    2113             :             }
    2114             :             else
    2115             :             {
    2116             :                 const_cast<GDALDefaultRasterAttributeTable *>(this)
    2117           2 :                     ->osWorkingResult.clear();
    2118             :             }
    2119          10 :             delete poGeom;
    2120          10 :             return osWorkingResult;
    2121             :         }
    2122             :     }
    2123             : 
    2124           0 :     return "";
    2125             : }
    2126             : 
    2127             : /************************************************************************/
    2128             : /*                      GDALRATGetValueAsString()                       */
    2129             : /************************************************************************/
    2130             : /**
    2131             :  * \brief Fetch field value as a string.
    2132             :  *
    2133             :  * This function is the same as the C++ method
    2134             :  * GDALRasterAttributeTable::GetValueAsString()
    2135             :  */
    2136         259 : const char *CPL_STDCALL GDALRATGetValueAsString(GDALRasterAttributeTableH hRAT,
    2137             :                                                 int iRow, int iField)
    2138             : 
    2139             : {
    2140         259 :     VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsString", nullptr);
    2141             : 
    2142         518 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsString(iRow,
    2143         259 :                                                                         iField);
    2144             : }
    2145             : 
    2146             : /************************************************************************/
    2147             : /*                           GetValueAsInt()                            */
    2148             : /************************************************************************/
    2149             : 
    2150         642 : int GDALDefaultRasterAttributeTable::GetValueAsInt(int iRow, int iField) const
    2151             : 
    2152             : {
    2153         642 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2154             :     {
    2155          21 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2156             :                  iField);
    2157             : 
    2158          21 :         return 0;
    2159             :     }
    2160             : 
    2161         621 :     if (iRow < 0 || iRow >= nRowCount)
    2162             :     {
    2163           3 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2164             : 
    2165           3 :         return 0;
    2166             :     }
    2167             : 
    2168         618 :     switch (aoFields[iField].eType)
    2169             :     {
    2170         609 :         case GFT_Integer:
    2171         609 :             return aoFields[iField].anValues[iRow];
    2172             : 
    2173           1 :         case GFT_Real:
    2174           1 :             return static_cast<int>(aoFields[iField].adfValues[iRow]);
    2175             : 
    2176           1 :         case GFT_String:
    2177           1 :             return atoi(aoFields[iField].aosValues[iRow].c_str());
    2178             : 
    2179           5 :         case GFT_Boolean:
    2180           5 :             return aoFields[iField].abValues[iRow];
    2181             : 
    2182           2 :         case GFT_DateTime:
    2183             :         case GFT_WKBGeometry:
    2184           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2185             :                      "Incompatible RAT field type");
    2186           2 :             break;
    2187             :     }
    2188             : 
    2189           2 :     return 0;
    2190             : }
    2191             : 
    2192             : /************************************************************************/
    2193             : /*                        GDALRATGetValueAsInt()                        */
    2194             : /************************************************************************/
    2195             : 
    2196             : /**
    2197             :  * \brief Fetch field value as a integer.
    2198             :  *
    2199             :  * This function is the same as the C++ method
    2200             :  * GDALRasterAttributeTable::GetValueAsInt()
    2201             :  */
    2202         305 : int CPL_STDCALL GDALRATGetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
    2203             :                                      int iField)
    2204             : 
    2205             : {
    2206         305 :     VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsInt", 0);
    2207             : 
    2208         610 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsInt(iRow,
    2209         305 :                                                                      iField);
    2210             : }
    2211             : 
    2212             : /************************************************************************/
    2213             : /*                          GetValueAsDouble()                          */
    2214             : /************************************************************************/
    2215             : 
    2216         775 : double GDALDefaultRasterAttributeTable::GetValueAsDouble(int iRow,
    2217             :                                                          int iField) const
    2218             : 
    2219             : {
    2220         775 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2221             :     {
    2222           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2223             :                  iField);
    2224             : 
    2225           1 :         return 0;
    2226             :     }
    2227             : 
    2228         774 :     if (iRow < 0 || iRow >= nRowCount)
    2229             :     {
    2230           3 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2231             : 
    2232           3 :         return 0;
    2233             :     }
    2234             : 
    2235         771 :     switch (aoFields[iField].eType)
    2236             :     {
    2237           1 :         case GFT_Integer:
    2238           1 :             return aoFields[iField].anValues[iRow];
    2239             : 
    2240         766 :         case GFT_Real:
    2241         766 :             return aoFields[iField].adfValues[iRow];
    2242             : 
    2243           1 :         case GFT_String:
    2244           1 :             return CPLAtof(aoFields[iField].aosValues[iRow].c_str());
    2245             : 
    2246           1 :         case GFT_Boolean:
    2247           1 :             return aoFields[iField].abValues[iRow];
    2248             : 
    2249           2 :         case GFT_DateTime:
    2250             :         case GFT_WKBGeometry:
    2251           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2252             :                      "Incompatible RAT field type");
    2253           2 :             break;
    2254             :     }
    2255             : 
    2256           2 :     return 0;
    2257             : }
    2258             : 
    2259             : /************************************************************************/
    2260             : /*                      GDALRATGetValueAsDouble()                       */
    2261             : /************************************************************************/
    2262             : 
    2263             : /**
    2264             :  * \brief Fetch field value as a double.
    2265             :  *
    2266             :  * This function is the same as the C++ method
    2267             :  * GDALRasterAttributeTable::GetValueAsDouble()
    2268             :  */
    2269         243 : double CPL_STDCALL GDALRATGetValueAsDouble(GDALRasterAttributeTableH hRAT,
    2270             :                                            int iRow, int iField)
    2271             : 
    2272             : {
    2273         243 :     VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsDouble", 0);
    2274             : 
    2275         486 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDouble(iRow,
    2276         243 :                                                                         iField);
    2277             : }
    2278             : 
    2279             : /************************************************************************/
    2280             : /*                         GetValueAsBoolean()                          */
    2281             : /************************************************************************/
    2282             : 
    2283          51 : bool GDALDefaultRasterAttributeTable::GetValueAsBoolean(int iRow,
    2284             :                                                         int iField) const
    2285             : 
    2286             : {
    2287          51 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2288             :     {
    2289           6 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2290             :                  iField);
    2291             : 
    2292           6 :         return false;
    2293             :     }
    2294             : 
    2295          45 :     if (iRow < 0 || iRow >= nRowCount)
    2296             :     {
    2297           2 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2298             : 
    2299           2 :         return false;
    2300             :     }
    2301             : 
    2302          43 :     switch (aoFields[iField].eType)
    2303             :     {
    2304           5 :         case GFT_Integer:
    2305           5 :             return aoFields[iField].anValues[iRow] != 0;
    2306             : 
    2307           1 :         case GFT_Real:
    2308           1 :             return aoFields[iField].adfValues[iRow] != 0;
    2309             : 
    2310           1 :         case GFT_String:
    2311           1 :             return CPLTestBool(aoFields[iField].aosValues[iRow].c_str());
    2312             : 
    2313          34 :         case GFT_Boolean:
    2314          34 :             return aoFields[iField].abValues[iRow];
    2315             : 
    2316           2 :         case GFT_DateTime:
    2317             :         case GFT_WKBGeometry:
    2318           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2319             :                      "Incompatible RAT field type");
    2320           2 :             break;
    2321             :     }
    2322             : 
    2323           2 :     return false;
    2324             : }
    2325             : 
    2326             : /************************************************************************/
    2327             : /*                      GDALRATGetValueAsBoolean()                      */
    2328             : /************************************************************************/
    2329             : 
    2330             : /**
    2331             :  * \brief Fetch field value as a boolean.
    2332             :  *
    2333             :  * This function is the same as the C++ method
    2334             :  * GDALRasterAttributeTable::GetValueAsBoolean()
    2335             :  *
    2336             :  * \since 3.12
    2337             :  */
    2338          22 : bool GDALRATGetValueAsBoolean(GDALRasterAttributeTableH hRAT, int iRow,
    2339             :                               int iField)
    2340             : 
    2341             : {
    2342          22 :     VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsBoolean", false);
    2343             : 
    2344          44 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsBoolean(
    2345          22 :         iRow, iField);
    2346             : }
    2347             : 
    2348             : /************************************************************************/
    2349             : /*                         GetValueAsDateTime()                         */
    2350             : /************************************************************************/
    2351             : 
    2352             : GDALRATDateTime
    2353          18 : GDALDefaultRasterAttributeTable::GetValueAsDateTime(int iRow, int iField) const
    2354             : 
    2355             : {
    2356          18 :     GDALRATDateTime dt;
    2357             : 
    2358          18 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2359             :     {
    2360           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2361             :                  iField);
    2362             : 
    2363           1 :         return dt;
    2364             :     }
    2365             : 
    2366          17 :     if (iRow < 0 || iRow >= nRowCount)
    2367             :     {
    2368           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2369             : 
    2370           1 :         return dt;
    2371             :     }
    2372             : 
    2373          16 :     switch (aoFields[iField].eType)
    2374             :     {
    2375           0 :         case GFT_String:
    2376           0 :             StringToDateTime(aoFields[iField].aosValues[iRow].c_str(), dt);
    2377           0 :             break;
    2378             : 
    2379          12 :         case GFT_DateTime:
    2380          12 :             dt = aoFields[iField].asDateTimeValues[iRow];
    2381          12 :             break;
    2382             : 
    2383           4 :         case GFT_Integer:
    2384             :         case GFT_Real:
    2385             :         case GFT_Boolean:
    2386             :         case GFT_WKBGeometry:
    2387           4 :             CPLError(CE_Failure, CPLE_AppDefined,
    2388             :                      "Incompatible RAT field type");
    2389           4 :             break;
    2390             :     }
    2391             : 
    2392          16 :     return dt;
    2393             : }
    2394             : 
    2395             : /************************************************************************/
    2396             : /*                     GDALRATGetValueAsDateTime()                      */
    2397             : /************************************************************************/
    2398             : 
    2399             : /**
    2400             :  * \brief Fetch field value as a datetime.
    2401             :  *
    2402             :  * The value of the requested column in the requested row is returned
    2403             :  * as a datetime. Besides being called on a GFT_DateTime field, it
    2404             :  * is also possible to call this method on a string field that contains a
    2405             :  * ISO-8601 encoded datetime.
    2406             :  *
    2407             :  * This function is the same as the C++ method
    2408             :  * GDALRasterAttributeTable::GetValueAsDateTime()
    2409             :  *
    2410             :  * @param hRAT Raster attribute table handle. Must NOT be null.
    2411             :  * @param iRow Row index (0-based indexing)
    2412             :  * @param iField Field index (0-based indexing)
    2413             :  * @param[out] psDateTime Output date time struct. Must NOT be null.
    2414             :  * @return error code.
    2415             :  *
    2416             :  * \since 3.12
    2417             :  */
    2418          16 : CPLErr GDALRATGetValueAsDateTime(GDALRasterAttributeTableH hRAT, int iRow,
    2419             :                                  int iField, GDALRATDateTime *psDateTime)
    2420             : 
    2421             : {
    2422          16 :     VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsBoolean", CE_Failure);
    2423          16 :     VALIDATE_POINTER1(psDateTime, "GDALRATGetValueAsBoolean", CE_Failure);
    2424             : 
    2425          16 :     const auto nErrorCounter = CPLGetErrorCounter();
    2426          16 :     *psDateTime =
    2427          16 :         GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDateTime(iRow,
    2428          16 :                                                                        iField);
    2429          16 :     return nErrorCounter == CPLGetErrorCounter() ? CE_None : CE_Failure;
    2430             : }
    2431             : 
    2432             : /************************************************************************/
    2433             : /*                       GetValueAsWKBGeometry()                        */
    2434             : /************************************************************************/
    2435             : 
    2436             : const GByte *
    2437          15 : GDALDefaultRasterAttributeTable::GetValueAsWKBGeometry(int iRow, int iField,
    2438             :                                                        size_t &nWKBSize) const
    2439             : 
    2440             : {
    2441          15 :     nWKBSize = 0;
    2442             : 
    2443          15 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2444             :     {
    2445           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2446             :                  iField);
    2447             : 
    2448           1 :         return nullptr;
    2449             :     }
    2450             : 
    2451          14 :     if (iRow < 0 || iRow >= nRowCount)
    2452             :     {
    2453           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2454             : 
    2455           1 :         return nullptr;
    2456             :     }
    2457             : 
    2458          13 :     switch (aoFields[iField].eType)
    2459             :     {
    2460           0 :         case GFT_String:
    2461             :         {
    2462             :             auto abyWKB =
    2463           0 :                 WKTGeometryToWKB(aoFields[iField].aosValues[iRow].c_str());
    2464           0 :             if (!abyWKB.empty())
    2465             :             {
    2466           0 :                 nWKBSize = abyWKB.size();
    2467           0 :                 m_abyWKB = std::move(abyWKB);
    2468           0 :                 return m_abyWKB.data();
    2469             :             }
    2470           0 :             return nullptr;
    2471             :         }
    2472             : 
    2473           9 :         case GFT_WKBGeometry:
    2474             :         {
    2475           9 :             nWKBSize = aoFields[iField].aabyWKBGeometryValues[iRow].size();
    2476           9 :             return nWKBSize
    2477           9 :                        ? aoFields[iField].aabyWKBGeometryValues[iRow].data()
    2478           9 :                        : nullptr;
    2479             :         }
    2480             : 
    2481           4 :         case GFT_Integer:
    2482             :         case GFT_Real:
    2483             :         case GFT_Boolean:
    2484             :         case GFT_DateTime:
    2485           4 :             CPLError(CE_Failure, CPLE_AppDefined,
    2486             :                      "Incompatible RAT field type");
    2487           4 :             break;
    2488             :     }
    2489             : 
    2490           4 :     return nullptr;
    2491             : }
    2492             : 
    2493             : /************************************************************************/
    2494             : /*                    GDALRATGetValueAsWKBGeometry()                    */
    2495             : /************************************************************************/
    2496             : 
    2497             : /**
    2498             :  * \brief Fetch field value as a WKB-encoded geometry.
    2499             :  *
    2500             :  * The value of the requested column in the requested row is returned
    2501             :  * as a WKB geometry. Besides being called on a GFT_WKBGeometry field, it
    2502             :  * is also possible to call this method on a string field that contains a WKT
    2503             :  * encoded geometry.
    2504             :  *
    2505             :  * The returned pointer may be invalidated by a following call  call to a method
    2506             :  * of this GDALRasterAttributeTable instance.
    2507             :  *
    2508             :  * This function is the same as the C++ method
    2509             :  * GDALRasterAttributeTable::GetValueAsWKBGeometry()
    2510             :  *
    2511             :  * \since 3.12
    2512             :  */
    2513          14 : const GByte *GDALRATGetValueAsWKBGeometry(GDALRasterAttributeTableH hRAT,
    2514             :                                           int iRow, int iField,
    2515             :                                           size_t *pnWKBSize)
    2516             : 
    2517             : {
    2518          14 :     VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsWKBGeometry", nullptr);
    2519          14 :     VALIDATE_POINTER1(pnWKBSize, "GDALRATGetValueAsWKBGeometry", nullptr);
    2520             : 
    2521          28 :     return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsWKBGeometry(
    2522          14 :         iRow, iField, *pnWKBSize);
    2523             : }
    2524             : 
    2525             : /************************************************************************/
    2526             : /*                            SetRowCount()                             */
    2527             : /************************************************************************/
    2528             : 
    2529             : /** Set row count.
    2530             :  * @param nNewCount new count.
    2531             :  */
    2532        4770 : void GDALDefaultRasterAttributeTable::SetRowCount(int nNewCount)
    2533             : 
    2534             : {
    2535        4770 :     if (nNewCount == nRowCount)
    2536        1823 :         return;
    2537             : 
    2538        9845 :     for (auto &oField : aoFields)
    2539             :     {
    2540        6898 :         switch (oField.eType)
    2541             :         {
    2542        2564 :             case GFT_Integer:
    2543        2564 :                 oField.anValues.resize(nNewCount);
    2544        2564 :                 break;
    2545             : 
    2546        2806 :             case GFT_Real:
    2547        2806 :                 oField.adfValues.resize(nNewCount);
    2548        2806 :                 break;
    2549             : 
    2550        1480 :             case GFT_String:
    2551        1480 :                 oField.aosValues.resize(nNewCount);
    2552        1480 :                 break;
    2553             : 
    2554          20 :             case GFT_Boolean:
    2555          20 :                 oField.abValues.resize(nNewCount);
    2556          20 :                 break;
    2557             : 
    2558          15 :             case GFT_DateTime:
    2559          15 :                 oField.asDateTimeValues.resize(nNewCount);
    2560          15 :                 break;
    2561             : 
    2562          13 :             case GFT_WKBGeometry:
    2563          13 :                 oField.aabyWKBGeometryValues.resize(nNewCount);
    2564          13 :                 break;
    2565             :         }
    2566             :     }
    2567             : 
    2568        2947 :     nRowCount = nNewCount;
    2569             : }
    2570             : 
    2571             : /************************************************************************/
    2572             : /*                              SetValue()                              */
    2573             : /************************************************************************/
    2574             : 
    2575             : /** Set value
    2576             :  * @param iRow row index.
    2577             :  * @param iField field index.
    2578             :  * @param pszValue value.
    2579             :  */
    2580        5442 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
    2581             :                                                  const char *pszValue)
    2582             : 
    2583             : {
    2584        5442 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2585             :     {
    2586           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2587             :                  iField);
    2588             : 
    2589           1 :         return CE_Failure;
    2590             :     }
    2591             : 
    2592        5441 :     if (iRow == nRowCount)
    2593        1824 :         SetRowCount(nRowCount + 1);
    2594             : 
    2595        5441 :     if (iRow < 0 || iRow >= nRowCount)
    2596             :     {
    2597           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2598             : 
    2599           1 :         return CE_Failure;
    2600             :     }
    2601             : 
    2602        5440 :     switch (aoFields[iField].eType)
    2603             :     {
    2604         315 :         case GFT_Integer:
    2605         315 :             aoFields[iField].anValues[iRow] = atoi(pszValue);
    2606         315 :             break;
    2607             : 
    2608        2333 :         case GFT_Real:
    2609        2333 :             aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
    2610        2333 :             break;
    2611             : 
    2612        2748 :         case GFT_String:
    2613        2748 :             aoFields[iField].aosValues[iRow] = pszValue;
    2614        2748 :             break;
    2615             : 
    2616          14 :         case GFT_Boolean:
    2617          14 :             aoFields[iField].abValues[iRow] = CPLTestBool(pszValue);
    2618          14 :             break;
    2619             : 
    2620          15 :         case GFT_DateTime:
    2621             :         {
    2622          15 :             GDALRATDateTime sDateTime;
    2623          15 :             StringToDateTime(pszValue, sDateTime);
    2624          15 :             aoFields[iField].asDateTimeValues[iRow] = std::move(sDateTime);
    2625          15 :             break;
    2626             :         }
    2627             : 
    2628          15 :         case GFT_WKBGeometry:
    2629             :         {
    2630          30 :             auto abyWKB = WKTGeometryToWKB(pszValue);
    2631          15 :             aoFields[iField].aabyWKBGeometryValues[iRow] = std::move(abyWKB);
    2632          15 :             break;
    2633             :         }
    2634             :     }
    2635             : 
    2636        5440 :     return CE_None;
    2637             : }
    2638             : 
    2639             : /************************************************************************/
    2640             : /*                      GDALRATSetValueAsString()                       */
    2641             : /************************************************************************/
    2642             : 
    2643             : /**
    2644             :  * \brief Set field value from string.
    2645             :  *
    2646             :  * This function is the same as the C++ method
    2647             :  * GDALRasterAttributeTable::SetValue()
    2648             :  * @param hRAT RAT handle.
    2649             :  * @param iRow row index.
    2650             :  * @param iField field index.
    2651             :  * @param pszValue value.
    2652             :  */
    2653         214 : void CPL_STDCALL GDALRATSetValueAsString(GDALRasterAttributeTableH hRAT,
    2654             :                                          int iRow, int iField,
    2655             :                                          const char *pszValue)
    2656             : 
    2657             : {
    2658         214 :     VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsString");
    2659             : 
    2660         214 :     GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
    2661         214 :                                                          pszValue);
    2662             : }
    2663             : 
    2664             : /************************************************************************/
    2665             : /*                              SetValue()                              */
    2666             : /************************************************************************/
    2667             : 
    2668        2897 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
    2669             :                                                  int nValue)
    2670             : 
    2671             : {
    2672        2897 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2673             :     {
    2674           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2675             :                  iField);
    2676             : 
    2677           1 :         return CE_Failure;
    2678             :     }
    2679             : 
    2680        2896 :     if (iRow == nRowCount)
    2681         792 :         SetRowCount(nRowCount + 1);
    2682             : 
    2683        2896 :     if (iRow < 0 || iRow >= nRowCount)
    2684             :     {
    2685           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2686             : 
    2687           1 :         return CE_Failure;
    2688             :     }
    2689             : 
    2690        2895 :     switch (aoFields[iField].eType)
    2691             :     {
    2692        2882 :         case GFT_Integer:
    2693        2882 :             aoFields[iField].anValues[iRow] = nValue;
    2694        2882 :             break;
    2695             : 
    2696           7 :         case GFT_Real:
    2697           7 :             aoFields[iField].adfValues[iRow] = nValue;
    2698           7 :             break;
    2699             : 
    2700           1 :         case GFT_String:
    2701             :         {
    2702             :             char szValue[100];
    2703             : 
    2704           1 :             snprintf(szValue, sizeof(szValue), "%d", nValue);
    2705           1 :             aoFields[iField].aosValues[iRow] = szValue;
    2706           1 :             break;
    2707             :         }
    2708             : 
    2709           3 :         case GFT_Boolean:
    2710           3 :             aoFields[iField].abValues[iRow] = nValue != 0;
    2711           3 :             break;
    2712             : 
    2713           2 :         case GFT_DateTime:
    2714             :         case GFT_WKBGeometry:
    2715           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2716             :                      "Incompatible RAT field type");
    2717           2 :             return CE_Failure;
    2718             :     }
    2719             : 
    2720        2893 :     return CE_None;
    2721             : }
    2722             : 
    2723             : /************************************************************************/
    2724             : /*                        GDALRATSetValueAsInt()                        */
    2725             : /************************************************************************/
    2726             : 
    2727             : /**
    2728             :  * \brief Set field value from integer.
    2729             :  *
    2730             :  * This function is the same as the C++ method
    2731             :  * GDALRasterAttributeTable::SetValue()
    2732             :  */
    2733         295 : void CPL_STDCALL GDALRATSetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
    2734             :                                       int iField, int nValue)
    2735             : 
    2736             : {
    2737         295 :     VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsInt");
    2738             : 
    2739         295 :     GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, nValue);
    2740             : }
    2741             : 
    2742             : /************************************************************************/
    2743             : /*                              SetValue()                              */
    2744             : /************************************************************************/
    2745             : 
    2746        6483 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
    2747             :                                                  double dfValue)
    2748             : 
    2749             : {
    2750        6483 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2751             :     {
    2752           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2753             :                  iField);
    2754             : 
    2755           1 :         return CE_Failure;
    2756             :     }
    2757             : 
    2758        6482 :     if (iRow == nRowCount)
    2759           0 :         SetRowCount(nRowCount + 1);
    2760             : 
    2761        6482 :     if (iRow < 0 || iRow >= nRowCount)
    2762             :     {
    2763           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2764             : 
    2765           1 :         return CE_Failure;
    2766             :     }
    2767             : 
    2768        6481 :     switch (aoFields[iField].eType)
    2769             :     {
    2770        1591 :         case GFT_Integer:
    2771        1591 :             aoFields[iField].anValues[iRow] = static_cast<int>(dfValue);
    2772        1591 :             break;
    2773             : 
    2774        4884 :         case GFT_Real:
    2775        4884 :             aoFields[iField].adfValues[iRow] = dfValue;
    2776        4884 :             break;
    2777             : 
    2778           1 :         case GFT_String:
    2779             :         {
    2780           1 :             char szValue[100] = {'\0'};
    2781             : 
    2782           1 :             CPLsnprintf(szValue, sizeof(szValue), "%.15g", dfValue);
    2783           1 :             aoFields[iField].aosValues[iRow] = szValue;
    2784           1 :             break;
    2785             :         }
    2786             : 
    2787           1 :         case GFT_Boolean:
    2788           1 :             aoFields[iField].abValues[iRow] = dfValue != 0;
    2789           1 :             break;
    2790             : 
    2791           4 :         case GFT_DateTime:
    2792             :         case GFT_WKBGeometry:
    2793           4 :             CPLError(CE_Failure, CPLE_AppDefined,
    2794             :                      "Incompatible RAT field type");
    2795           4 :             return CE_Failure;
    2796             :     }
    2797             : 
    2798        6477 :     return CE_None;
    2799             : }
    2800             : 
    2801             : /************************************************************************/
    2802             : /*                      GDALRATSetValueAsDouble()                       */
    2803             : /************************************************************************/
    2804             : 
    2805             : /**
    2806             :  * \brief Set field value from double.
    2807             :  *
    2808             :  * This function is the same as the C++ method
    2809             :  * GDALRasterAttributeTable::SetValue()
    2810             :  */
    2811         196 : void CPL_STDCALL GDALRATSetValueAsDouble(GDALRasterAttributeTableH hRAT,
    2812             :                                          int iRow, int iField, double dfValue)
    2813             : 
    2814             : {
    2815         196 :     VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsDouble");
    2816             : 
    2817         196 :     GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, dfValue);
    2818             : }
    2819             : 
    2820             : /************************************************************************/
    2821             : /*                              SetValue()                              */
    2822             : /************************************************************************/
    2823             : 
    2824          29 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
    2825             :                                                  bool bValue)
    2826             : 
    2827             : {
    2828          29 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2829             :     {
    2830           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2831             :                  iField);
    2832             : 
    2833           1 :         return CE_Failure;
    2834             :     }
    2835             : 
    2836          28 :     if (iRow == nRowCount)
    2837           1 :         SetRowCount(nRowCount + 1);
    2838             : 
    2839          28 :     if (iRow < 0 || iRow >= nRowCount)
    2840             :     {
    2841           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2842             : 
    2843           1 :         return CE_Failure;
    2844             :     }
    2845             : 
    2846          27 :     switch (aoFields[iField].eType)
    2847             :     {
    2848           1 :         case GFT_Integer:
    2849             :         {
    2850           1 :             aoFields[iField].anValues[iRow] = bValue ? 1 : 0;
    2851           1 :             break;
    2852             :         }
    2853           1 :         case GFT_String:
    2854             :         {
    2855           1 :             aoFields[iField].aosValues[iRow] = bValue ? "true" : "false";
    2856           1 :             break;
    2857             :         }
    2858           1 :         case GFT_Real:
    2859             :         {
    2860           1 :             aoFields[iField].adfValues[iRow] = bValue ? 1 : 0;
    2861           1 :             break;
    2862             :         }
    2863          22 :         case GFT_Boolean:
    2864             :         {
    2865          22 :             aoFields[iField].abValues[iRow] = bValue;
    2866          22 :             break;
    2867             :         }
    2868           2 :         case GFT_DateTime:
    2869             :         case GFT_WKBGeometry:
    2870           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2871             :                      "Incompatible RAT field type");
    2872           2 :             return CE_Failure;
    2873             :     }
    2874             : 
    2875          25 :     return CE_None;
    2876             : }
    2877             : 
    2878             : /************************************************************************/
    2879             : /*                      GDALRATSetValueAsBoolean()                      */
    2880             : /************************************************************************/
    2881             : 
    2882             : /**
    2883             :  * \brief Set field value from a boolean value.
    2884             :  *
    2885             :  * This function is the same as the C++ method
    2886             :  * GDALRasterAttributeTable::SetValue()
    2887             :  *
    2888             :  * \since 3.12
    2889             :  */
    2890          29 : CPLErr GDALRATSetValueAsBoolean(GDALRasterAttributeTableH hRAT, int iRow,
    2891             :                                 int iField, bool bValue)
    2892             : 
    2893             : {
    2894          29 :     VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsBoolean", CE_Failure);
    2895             : 
    2896          58 :     return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
    2897          29 :                                                                 bValue);
    2898             : }
    2899             : 
    2900             : /************************************************************************/
    2901             : /*                              SetValue()                              */
    2902             : /************************************************************************/
    2903             : 
    2904             : CPLErr
    2905          14 : GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
    2906             :                                           const GDALRATDateTime &sDateTime)
    2907             : 
    2908             : {
    2909          14 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2910             :     {
    2911           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2912             :                  iField);
    2913             : 
    2914           1 :         return CE_Failure;
    2915             :     }
    2916             : 
    2917          13 :     if (iRow == nRowCount)
    2918           0 :         SetRowCount(nRowCount + 1);
    2919             : 
    2920          13 :     if (iRow < 0 || iRow >= nRowCount)
    2921             :     {
    2922           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    2923             : 
    2924           1 :         return CE_Failure;
    2925             :     }
    2926             : 
    2927          12 :     switch (aoFields[iField].eType)
    2928             :     {
    2929           1 :         case GFT_String:
    2930             :         {
    2931           1 :             aoFields[iField].aosValues[iRow] = DateTimeToString(sDateTime);
    2932           1 :             break;
    2933             :         }
    2934             : 
    2935           7 :         case GFT_DateTime:
    2936             :         {
    2937           7 :             aoFields[iField].asDateTimeValues[iRow] = sDateTime;
    2938           7 :             break;
    2939             :         }
    2940             : 
    2941           4 :         case GFT_Integer:
    2942             :         case GFT_Real:
    2943             :         case GFT_Boolean:
    2944             :         case GFT_WKBGeometry:
    2945           4 :             CPLError(CE_Failure, CPLE_AppDefined,
    2946             :                      "Incompatible RAT field type");
    2947           4 :             return CE_Failure;
    2948             :     }
    2949             : 
    2950           8 :     return CE_None;
    2951             : }
    2952             : 
    2953             : /************************************************************************/
    2954             : /*                     GDALRATSetValueAsDateTime()                      */
    2955             : /************************************************************************/
    2956             : 
    2957             : /**
    2958             :  * \brief Set field value from datetime.
    2959             :  *
    2960             :  * Note that the GDALRATDateTime::bIsValid field must be set to true if
    2961             :  * the date time is valid.
    2962             :  *
    2963             :  * This function is the same as the C++ method
    2964             :  * GDALRasterAttributeTable::SetValue()
    2965             :  *
    2966             :  * \since 3.12
    2967             :  */
    2968          16 : CPLErr GDALRATSetValueAsDateTime(GDALRasterAttributeTableH hRAT, int iRow,
    2969             :                                  int iField, const GDALRATDateTime *psDateTime)
    2970             : 
    2971             : {
    2972          16 :     VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsDateTime", CE_Failure);
    2973          16 :     VALIDATE_POINTER1(psDateTime, "GDALRATSetValueAsDateTime", CE_Failure);
    2974             : 
    2975          32 :     return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
    2976          16 :                                                                 *psDateTime);
    2977             : }
    2978             : 
    2979             : /************************************************************************/
    2980             : /*                              SetValue()                              */
    2981             : /************************************************************************/
    2982             : 
    2983           9 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
    2984             :                                                  const void *pabyWKB,
    2985             :                                                  size_t nWKBSize)
    2986             : 
    2987             : {
    2988           9 :     if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
    2989             :     {
    2990           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
    2991             :                  iField);
    2992             : 
    2993           1 :         return CE_Failure;
    2994             :     }
    2995             : 
    2996           8 :     if (iRow == nRowCount)
    2997           0 :         SetRowCount(nRowCount + 1);
    2998             : 
    2999           8 :     if (iRow < 0 || iRow >= nRowCount)
    3000             :     {
    3001           1 :         CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
    3002             : 
    3003           1 :         return CE_Failure;
    3004             :     }
    3005             : 
    3006           7 :     switch (aoFields[iField].eType)
    3007             :     {
    3008           1 :         case GFT_String:
    3009             :         {
    3010           1 :             aoFields[iField].aosValues[iRow] =
    3011           2 :                 WKBGeometryToWKT(pabyWKB, nWKBSize);
    3012           1 :             break;
    3013             :         }
    3014             : 
    3015           2 :         case GFT_WKBGeometry:
    3016             :         {
    3017           2 :             if (nWKBSize)
    3018           2 :                 aoFields[iField].aabyWKBGeometryValues[iRow].assign(
    3019             :                     static_cast<const GByte *>(pabyWKB),
    3020             :                     static_cast<const GByte *>(pabyWKB) + nWKBSize);
    3021             :             else
    3022           0 :                 aoFields[iField].aabyWKBGeometryValues[iRow].clear();
    3023           2 :             break;
    3024             :         }
    3025             : 
    3026           4 :         case GFT_Integer:
    3027             :         case GFT_Real:
    3028             :         case GFT_Boolean:
    3029             :         case GFT_DateTime:
    3030           4 :             CPLError(CE_Failure, CPLE_AppDefined,
    3031             :                      "Incompatible RAT field type");
    3032           4 :             return CE_Failure;
    3033             :     }
    3034             : 
    3035           3 :     return CE_None;
    3036             : }
    3037             : 
    3038             : /************************************************************************/
    3039             : /*                    GDALRATSetValueAsWKBGeometry()                    */
    3040             : /************************************************************************/
    3041             : 
    3042             : /**
    3043             :  * \brief Set field value from a WKB-encoded geometry.
    3044             :  *
    3045             :  * This function is the same as the C++ method
    3046             :  * GDALRasterAttributeTable::SetValue()
    3047             :  *
    3048             :  * \since 3.12
    3049             :  */
    3050          14 : CPLErr GDALRATSetValueAsWKBGeometry(GDALRasterAttributeTableH hRAT, int iRow,
    3051             :                                     int iField, const void *pabyWKB,
    3052             :                                     size_t nWKBSize)
    3053             : 
    3054             : {
    3055          14 :     VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsWKBGeometry", CE_Failure);
    3056             : 
    3057          28 :     return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(
    3058          14 :         iRow, iField, pabyWKB, nWKBSize);
    3059             : }
    3060             : 
    3061             : /************************************************************************/
    3062             : /*                      ChangesAreWrittenToFile()                       */
    3063             : /************************************************************************/
    3064             : 
    3065           0 : int GDALDefaultRasterAttributeTable::ChangesAreWrittenToFile()
    3066             : {
    3067             :     // GDALRasterBand.SetDefaultRAT needs to be called on instances of
    3068             :     // GDALDefaultRasterAttributeTable since changes are just in-memory
    3069           0 :     return false;
    3070             : }
    3071             : 
    3072             : /************************************************************************/
    3073             : /*                   GDALRATChangesAreWrittenToFile()                   */
    3074             : /************************************************************************/
    3075             : 
    3076             : /**
    3077             :  * \brief Determine whether changes made to this RAT are reflected directly in
    3078             :  * the dataset
    3079             :  *
    3080             :  * This function is the same as the C++ method
    3081             :  * GDALRasterAttributeTable::ChangesAreWrittenToFile()
    3082             :  */
    3083           2 : int CPL_STDCALL GDALRATChangesAreWrittenToFile(GDALRasterAttributeTableH hRAT)
    3084             : {
    3085           2 :     VALIDATE_POINTER1(hRAT, "GDALRATChangesAreWrittenToFile", false);
    3086             : 
    3087           2 :     return GDALRasterAttributeTable::FromHandle(hRAT)
    3088           2 :         ->ChangesAreWrittenToFile();
    3089             : }
    3090             : 
    3091             : /************************************************************************/
    3092             : /*                           GetRowOfValue()                            */
    3093             : /************************************************************************/
    3094             : 
    3095           2 : int GDALDefaultRasterAttributeTable::GetRowOfValue(double dfValue) const
    3096             : 
    3097             : {
    3098             :     /* -------------------------------------------------------------------- */
    3099             :     /*      Handle case of regular binning.                                 */
    3100             :     /* -------------------------------------------------------------------- */
    3101           2 :     if (bLinearBinning)
    3102             :     {
    3103           0 :         const int iBin =
    3104           0 :             static_cast<int>(floor((dfValue - dfRow0Min) / dfBinSize));
    3105           0 :         if (iBin < 0 || iBin >= nRowCount)
    3106           0 :             return -1;
    3107             : 
    3108           0 :         return iBin;
    3109             :     }
    3110             : 
    3111             :     /* -------------------------------------------------------------------- */
    3112             :     /*      Do we have any information?                                     */
    3113             :     /* -------------------------------------------------------------------- */
    3114           2 :     if (!bColumnsAnalysed)
    3115           2 :         const_cast<GDALDefaultRasterAttributeTable *>(this)->AnalyseColumns();
    3116             : 
    3117           2 :     if (nMinCol == -1 && nMaxCol == -1)
    3118           0 :         return -1;
    3119             : 
    3120           2 :     const GDALRasterAttributeField *poMin = nullptr;
    3121           2 :     if (nMinCol != -1)
    3122           2 :         poMin = &(aoFields[nMinCol]);
    3123             :     else
    3124           0 :         poMin = nullptr;
    3125             : 
    3126           2 :     const GDALRasterAttributeField *poMax = nullptr;
    3127           2 :     if (nMaxCol != -1)
    3128           2 :         poMax = &(aoFields[nMaxCol]);
    3129             :     else
    3130           0 :         poMax = nullptr;
    3131             : 
    3132             :     /* -------------------------------------------------------------------- */
    3133             :     /*      Search through rows for match.                                  */
    3134             :     /* -------------------------------------------------------------------- */
    3135           4 :     for (int iRow = 0; iRow < nRowCount; iRow++)
    3136             :     {
    3137           4 :         if (poMin != nullptr)
    3138             :         {
    3139           4 :             if (poMin->eType == GFT_Integer)
    3140             :             {
    3141           4 :                 while (iRow < nRowCount && dfValue < poMin->anValues[iRow])
    3142           0 :                     iRow++;
    3143             :             }
    3144           0 :             else if (poMin->eType == GFT_Real)
    3145             :             {
    3146           0 :                 while (iRow < nRowCount && dfValue < poMin->adfValues[iRow])
    3147           0 :                     iRow++;
    3148             :             }
    3149             : 
    3150           4 :             if (iRow == nRowCount)
    3151           0 :                 break;
    3152             :         }
    3153             : 
    3154           4 :         if (poMax != nullptr)
    3155             :         {
    3156          14 :             if ((poMax->eType == GFT_Integer &&
    3157           6 :                  dfValue > poMax->anValues[iRow]) ||
    3158           2 :                 (poMax->eType == GFT_Real && dfValue > poMax->adfValues[iRow]))
    3159           2 :                 continue;
    3160             :         }
    3161             : 
    3162           2 :         return iRow;
    3163             :     }
    3164             : 
    3165           0 :     return -1;
    3166             : }
    3167             : 
    3168             : /************************************************************************/
    3169             : /*                           GetRowOfValue()                            */
    3170             : /*                                                                      */
    3171             : /*      Int arg for now just converted to double.  Perhaps we will      */
    3172             : /*      handle this in a special way some day?                          */
    3173             : /************************************************************************/
    3174             : 
    3175           0 : int GDALDefaultRasterAttributeTable::GetRowOfValue(int nValue) const
    3176             : 
    3177             : {
    3178           0 :     return GetRowOfValue(static_cast<double>(nValue));
    3179             : }
    3180             : 
    3181             : /************************************************************************/
    3182             : /*                          SetLinearBinning()                          */
    3183             : /************************************************************************/
    3184             : 
    3185          16 : CPLErr GDALDefaultRasterAttributeTable::SetLinearBinning(double dfRow0MinIn,
    3186             :                                                          double dfBinSizeIn)
    3187             : 
    3188             : {
    3189          16 :     bLinearBinning = true;
    3190          16 :     dfRow0Min = dfRow0MinIn;
    3191          16 :     dfBinSize = dfBinSizeIn;
    3192             : 
    3193          16 :     return CE_None;
    3194             : }
    3195             : 
    3196             : /************************************************************************/
    3197             : /*                          GetLinearBinning()                          */
    3198             : /************************************************************************/
    3199             : 
    3200          37 : int GDALDefaultRasterAttributeTable::GetLinearBinning(double *pdfRow0Min,
    3201             :                                                       double *pdfBinSize) const
    3202             : 
    3203             : {
    3204          37 :     if (!bLinearBinning)
    3205          35 :         return false;
    3206             : 
    3207           2 :     *pdfRow0Min = dfRow0Min;
    3208           2 :     *pdfBinSize = dfBinSize;
    3209             : 
    3210           2 :     return true;
    3211             : }
    3212             : 
    3213             : /************************************************************************/
    3214             : /*                            GetTableType()                            */
    3215             : /************************************************************************/
    3216             : 
    3217             : /**
    3218             :  * \brief Get RAT Table Type
    3219             :  *
    3220             :  * Returns whether table type is thematic or athematic
    3221             :  *
    3222             :  * This method is the same as the C function GDALRATGetTableType().
    3223             :  *
    3224             :  *
    3225             :  * @return GRTT_THEMATIC or GRTT_ATHEMATIC
    3226             :  */
    3227             : 
    3228          37 : GDALRATTableType GDALDefaultRasterAttributeTable::GetTableType() const
    3229             : {
    3230          37 :     return eTableType;
    3231             : }
    3232             : 
    3233             : /************************************************************************/
    3234             : /*                            SetTableType()                            */
    3235             : /************************************************************************/
    3236             : 
    3237             : /**
    3238             :  * \brief Set RAT Table Type
    3239             :  *
    3240             :  * Set whether table type is thematic or athematic
    3241             :  *
    3242             :  * This method is the same as the C function GDALRATSetTableType().
    3243             :  *
    3244             :  * @param eInTableType the new RAT table type (GRTT_THEMATIC or GRTT_ATHEMATIC)
    3245             :  *
    3246             :  *
    3247             :  * @return CE_None on success or CE_Failure on failure.
    3248             :  */
    3249             : 
    3250          86 : CPLErr GDALDefaultRasterAttributeTable::SetTableType(
    3251             :     const GDALRATTableType eInTableType)
    3252             : {
    3253          86 :     eTableType = eInTableType;
    3254          86 :     return CE_None;
    3255             : }
    3256             : 
    3257             : /************************************************************************/
    3258             : /*                            CreateColumn()                            */
    3259             : /************************************************************************/
    3260             : 
    3261             : CPLErr
    3262        1027 : GDALDefaultRasterAttributeTable::CreateColumn(const char *pszFieldName,
    3263             :                                               GDALRATFieldType eFieldType,
    3264             :                                               GDALRATFieldUsage eFieldUsage)
    3265             : 
    3266             : {
    3267        1027 :     const size_t iNewField = aoFields.size();
    3268             : 
    3269        1027 :     aoFields.resize(iNewField + 1);
    3270             : 
    3271        1027 :     aoFields[iNewField].sName = pszFieldName;
    3272             : 
    3273             :     // color columns should be int 0..255
    3274        1027 :     if ((eFieldUsage == GFU_Red) || (eFieldUsage == GFU_Green) ||
    3275         961 :         (eFieldUsage == GFU_Blue) || (eFieldUsage == GFU_Alpha))
    3276             :     {
    3277          73 :         eFieldType = GFT_Integer;
    3278             :     }
    3279        1027 :     aoFields[iNewField].eType = eFieldType;
    3280        1027 :     aoFields[iNewField].eUsage = eFieldUsage;
    3281             : 
    3282        1027 :     switch (eFieldType)
    3283             :     {
    3284         480 :         case GFT_Integer:
    3285         480 :             aoFields[iNewField].anValues.resize(nRowCount);
    3286         480 :             break;
    3287             : 
    3288         193 :         case GFT_Real:
    3289         193 :             aoFields[iNewField].adfValues.resize(nRowCount);
    3290         193 :             break;
    3291             : 
    3292         297 :         case GFT_String:
    3293         297 :             aoFields[iNewField].aosValues.resize(nRowCount);
    3294         297 :             break;
    3295             : 
    3296          23 :         case GFT_Boolean:
    3297          23 :             aoFields[iNewField].abValues.resize(nRowCount);
    3298          23 :             break;
    3299             : 
    3300          18 :         case GFT_DateTime:
    3301          18 :             aoFields[iNewField].asDateTimeValues.resize(nRowCount);
    3302          18 :             break;
    3303             : 
    3304          16 :         case GFT_WKBGeometry:
    3305          16 :             aoFields[iNewField].aabyWKBGeometryValues.resize(nRowCount);
    3306          16 :             break;
    3307             :     }
    3308        1027 :     return CE_None;
    3309             : }
    3310             : 
    3311             : /************************************************************************/
    3312             : /*                          RemoveStatistics()                          */
    3313             : /************************************************************************/
    3314             : 
    3315             : /**
    3316             :  * \brief Remove Statistics from RAT
    3317             :  *
    3318             :  * Remove statistics (such as histogram) from the RAT. This is important
    3319             :  * if these have been invalidated, for example by cropping the image.
    3320             :  *
    3321             :  * This method is the same as the C function GDALRATRemoveStatistics().
    3322             :  *
    3323             :  */
    3324             : 
    3325           2 : void GDALDefaultRasterAttributeTable::RemoveStatistics()
    3326             : 
    3327             : {
    3328             :     // since we are storing the fields in a vector it will generally
    3329             :     // be faster to create a new vector and replace the old one
    3330             :     // rather than actually erasing columns.
    3331           4 :     std::vector<GDALRasterAttributeField> aoNewFields;
    3332           4 :     for (const auto &field : aoFields)
    3333             :     {
    3334           2 :         switch (field.eUsage)
    3335             :         {
    3336           1 :             case GFU_PixelCount:
    3337             :             case GFU_Min:
    3338             :             case GFU_Max:
    3339             :             case GFU_RedMin:
    3340             :             case GFU_GreenMin:
    3341             :             case GFU_BlueMin:
    3342             :             case GFU_AlphaMin:
    3343             :             case GFU_RedMax:
    3344             :             case GFU_GreenMax:
    3345             :             case GFU_BlueMax:
    3346             :             case GFU_AlphaMax:
    3347             :             {
    3348           1 :                 break;
    3349             :             }
    3350             : 
    3351           1 :             default:
    3352           1 :                 if (field.sName != "Histogram")
    3353             :                 {
    3354           1 :                     aoNewFields.push_back(field);
    3355             :                 }
    3356             :         }
    3357             :     }
    3358           2 :     aoFields = std::move(aoNewFields);
    3359           2 : }
    3360             : 
    3361             : /************************************************************************/
    3362             : /*                               Clone()                                */
    3363             : /************************************************************************/
    3364             : 
    3365          68 : GDALDefaultRasterAttributeTable *GDALDefaultRasterAttributeTable::Clone() const
    3366             : 
    3367             : {
    3368          68 :     return new GDALDefaultRasterAttributeTable(*this);
    3369             : }
    3370             : 
    3371             : /************************************************************************/
    3372             : /*                            GDALRATClone()                            */
    3373             : /************************************************************************/
    3374             : 
    3375             : /**
    3376             :  * \brief Copy Raster Attribute Table
    3377             :  *
    3378             :  * This function is the same as the C++ method GDALRasterAttributeTable::Clone()
    3379             :  */
    3380             : GDALRasterAttributeTableH CPL_STDCALL
    3381           6 : GDALRATClone(const GDALRasterAttributeTableH hRAT)
    3382             : 
    3383             : {
    3384           6 :     VALIDATE_POINTER1(hRAT, "GDALRATClone", nullptr);
    3385             : 
    3386           6 :     return GDALRasterAttributeTable::FromHandle(hRAT)->Clone();
    3387             : }
    3388             : 
    3389             : /************************************************************************/
    3390             : /*                        GDALRATSerializeJSON()                        */
    3391             : /************************************************************************/
    3392             : 
    3393             : /**
    3394             :  * \brief Serialize Raster Attribute Table in Json format
    3395             :  *
    3396             :  * This function is the same as the C++ method
    3397             :  * GDALRasterAttributeTable::SerializeJSON()
    3398             :  */
    3399           9 : void *CPL_STDCALL GDALRATSerializeJSON(GDALRasterAttributeTableH hRAT)
    3400             : 
    3401             : {
    3402           9 :     VALIDATE_POINTER1(hRAT, "GDALRATSerializeJSON", nullptr);
    3403             : 
    3404           9 :     return GDALRasterAttributeTable::FromHandle(hRAT)->SerializeJSON();
    3405             : }
    3406             : 
    3407             : /************************************************************************/
    3408             : /*                      GDALRATRemoveStatistics()                       */
    3409             : /************************************************************************/
    3410             : 
    3411             : /**
    3412             :  * \brief Remove Statistics from RAT
    3413             :  *
    3414             :  * This function is the same as the C++ method
    3415             :  * GDALRasterAttributeTable::RemoveStatistics()
    3416             :  *
    3417             :  */
    3418           1 : void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
    3419             : 
    3420             : {
    3421           1 :     VALIDATE_POINTER0(hRAT, "GDALRATRemoveStatistics");
    3422             : 
    3423           1 :     GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
    3424             : }
    3425             : 
    3426             : /************************************************************************/
    3427             : /*                        GDALLoadEsriCLRAsRAT()                        */
    3428             : /************************************************************************/
    3429             : 
    3430             : /**
    3431             :  * \brief Load a Esri .clr as a RAT.
    3432             :  *
    3433             :  * @param pszFilename .clr filename
    3434             :  *
    3435             :  * @return a new RAT, or nullptr in case of error.
    3436             :  *
    3437             :  * @since GDAL 3.14
    3438             :  */
    3439             : std::unique_ptr<GDALRasterAttributeTable>
    3440          88 : GDALLoadEsriCLRAsRAT(const char *pszFilename)
    3441             : {
    3442         176 :     auto fp = VSIFilesystemHandler::OpenStatic(pszFilename, "rb");
    3443          88 :     if (!fp)
    3444          80 :         return nullptr;
    3445             : 
    3446          16 :     auto poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
    3447           8 :     poRAT->CreateColumn("Value", GFT_Integer, GFU_Generic);
    3448           8 :     poRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
    3449           8 :     poRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
    3450           8 :     poRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
    3451             : 
    3452           8 :     int nRatRow = 0;
    3453             : 
    3454           8 :     constexpr int MAX_LINE_SIZE = 1000;  // Arbitary
    3455             :     while (const char *pszLine =
    3456         120 :                CPLReadLine2L(fp.get(), MAX_LINE_SIZE, nullptr))
    3457             :     {
    3458         112 :         if (*pszLine == '#' || *pszLine == '!')
    3459           0 :             continue;
    3460             : 
    3461             :         const CPLStringList aosTokens(
    3462         224 :             CSLTokenizeString2(pszLine, "\t ", CSLT_HONOURSTRINGS));
    3463             : 
    3464         112 :         if (aosTokens.size() >= 4)
    3465             :         {
    3466         112 :             const int nIndex = atoi(aosTokens[0]);
    3467         112 :             poRAT->SetValue(nRatRow, 0, nIndex);
    3468         112 :             poRAT->SetValue(nRatRow, 1, atoi(aosTokens[1]));
    3469         112 :             poRAT->SetValue(nRatRow, 2, atoi(aosTokens[2]));
    3470         112 :             poRAT->SetValue(nRatRow, 3, atoi(aosTokens[3]));
    3471         112 :             nRatRow++;
    3472             :         }
    3473         112 :     }
    3474             : 
    3475           8 :     return poRAT;
    3476             : }

Generated by: LCOV version 1.14