LCOV - code coverage report
Current view: top level - frmts/miramon - miramon_rasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 591 726 81.4 %
Date: 2026-03-05 10:33:42 Functions: 28 28 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  MiraMonRaster driver
       4             :  * Purpose:  Implements MMRRasterBand class: responsible for converting the
       5             :  *           information stored in an MMRBand into a GDAL RasterBand
       6             :  * Author:   Abel Pau
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2025, Xavier Pons
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : #include <algorithm>
      14             : 
      15             : #include "miramon_dataset.h"
      16             : #include "miramon_rasterband.h"
      17             : #include "miramon_band.h"  // Per a MMRBand
      18             : 
      19             : #include "../miramon_common/mm_gdal_functions.h"  // For MMCheck_REL_FILE()
      20             : 
      21             : /************************************************************************/
      22             : /*                           MMRRasterBand()                            */
      23             : /************************************************************************/
      24         210 : MMRRasterBand::MMRRasterBand(MMRDataset *poDSIn, int nBandIn)
      25         210 :     : m_pfRel(poDSIn->GetRel())
      26             : {
      27         210 :     poDS = poDSIn;
      28         210 :     nBand = nBandIn;
      29             : 
      30         210 :     eAccess = poDSIn->GetAccess();
      31             : 
      32         210 :     nRatOrCT = poDSIn->GetRatOrCT();
      33             : 
      34         210 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
      35         210 :     if (poBand == nullptr)
      36           0 :         return;
      37             : 
      38             :     // Getting some band info
      39         210 :     m_osBandSection = poBand->GetBandSection();
      40         210 :     m_eMMRDataTypeMiraMon = poBand->GeteMMDataType();
      41         210 :     m_eMMBytesPerPixel = poBand->GeteMMBytesPerPixel();
      42         210 :     SetUnitType(poBand->GetUnits());
      43         210 :     nBlockXSize = poBand->GetBlockXSize();
      44         210 :     nBlockYSize = poBand->GetBlockYSize();
      45             : 
      46         210 :     UpdateDataType();
      47             : 
      48             :     // We have a valid RasterBand.
      49         210 :     m_bIsValid = true;
      50             : }
      51             : 
      52             : /************************************************************************/
      53             : /*                           ~MMRRasterBand()                           */
      54             : /************************************************************************/
      55             : 
      56         420 : MMRRasterBand::~MMRRasterBand()
      57             : 
      58             : {
      59         210 :     FlushCache(true);
      60         420 : }
      61             : 
      62             : /************************************************************************/
      63             : /*                           UpdateDataType()                           */
      64             : /************************************************************************/
      65         210 : void MMRRasterBand::UpdateDataType()
      66             : {
      67         210 :     switch (m_eMMRDataTypeMiraMon)
      68             :     {
      69          65 :         case MMDataType::DATATYPE_AND_COMPR_BIT:
      70             :         case MMDataType::DATATYPE_AND_COMPR_BYTE:
      71             :         case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
      72          65 :             eDataType = GDT_UInt8;
      73          65 :             break;
      74             : 
      75          32 :         case MMDataType::DATATYPE_AND_COMPR_UINTEGER:
      76             :         case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
      77          32 :             eDataType = GDT_UInt16;
      78          32 :             break;
      79             : 
      80          29 :         case MMDataType::DATATYPE_AND_COMPR_INTEGER:
      81             :         case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
      82             :         case MMDataType::DATATYPE_AND_COMPR_INTEGER_ASCII:
      83          29 :             eDataType = GDT_Int16;
      84          29 :             break;
      85             : 
      86          27 :         case MMDataType::DATATYPE_AND_COMPR_LONG:
      87             :         case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
      88          27 :             eDataType = GDT_Int32;
      89          27 :             break;
      90             : 
      91          28 :         case MMDataType::DATATYPE_AND_COMPR_REAL:
      92             :         case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
      93             :         case MMDataType::DATATYPE_AND_COMPR_REAL_ASCII:
      94          28 :             eDataType = GDT_Float32;
      95          28 :             break;
      96             : 
      97          29 :         case MMDataType::DATATYPE_AND_COMPR_DOUBLE:
      98             :         case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
      99          29 :             eDataType = GDT_Float64;
     100          29 :             break;
     101             : 
     102           0 :         default:
     103           0 :             eDataType = GDT_UInt8;
     104             :             // This should really report an error, but this isn't
     105             :             // so easy from within constructors.
     106           0 :             CPLDebug("GDAL", "Unsupported pixel type in MMRRasterBand: %d.",
     107           0 :                      static_cast<int>(m_eMMRDataTypeMiraMon));
     108           0 :             break;
     109             :     }
     110         210 : }
     111             : 
     112             : /************************************************************************/
     113             : /*                           GetNoDataValue()                           */
     114             : /************************************************************************/
     115             : 
     116         280 : double MMRRasterBand::GetNoDataValue(int *pbSuccess)
     117             : 
     118             : {
     119         280 :     double dfNoData = 0.0;
     120         280 :     if (pbSuccess)
     121         260 :         *pbSuccess = FALSE;
     122             : 
     123         280 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     124         280 :     if (!poBand)
     125           0 :         return dfNoData;
     126             : 
     127         280 :     if (!poBand->BandHasNoData())
     128             :     {
     129          36 :         if (pbSuccess)
     130          36 :             *pbSuccess = FALSE;
     131          36 :         return dfNoData;
     132             :     }
     133             : 
     134         244 :     if (pbSuccess)
     135         224 :         *pbSuccess = TRUE;
     136         244 :     return poBand->GetNoDataValue();
     137             : }
     138             : 
     139             : /************************************************************************/
     140             : /*                             GetMinimum()                             */
     141             : /************************************************************************/
     142             : 
     143          35 : double MMRRasterBand::GetMinimum(int *pbSuccess)
     144             : 
     145             : {
     146          35 :     if (pbSuccess)
     147          35 :         *pbSuccess = FALSE;
     148             : 
     149          35 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     150          35 :     if (!poBand || !poBand->GetMinSet())
     151           1 :         return 0.0;
     152             : 
     153          34 :     if (pbSuccess)
     154          34 :         *pbSuccess = TRUE;
     155             : 
     156          34 :     return poBand->GetMin();
     157             : }
     158             : 
     159             : /************************************************************************/
     160             : /*                             GetMaximum()                             */
     161             : /************************************************************************/
     162             : 
     163          35 : double MMRRasterBand::GetMaximum(int *pbSuccess)
     164             : 
     165             : {
     166          35 :     if (pbSuccess)
     167          35 :         *pbSuccess = FALSE;
     168             : 
     169          35 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     170          35 :     if (!poBand || !poBand->GetMaxSet())
     171           1 :         return 0.0;
     172             : 
     173          34 :     if (pbSuccess)
     174          34 :         *pbSuccess = TRUE;
     175             : 
     176          34 :     return poBand->GetMax();
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                            GetUnitType()                             */
     181             : /************************************************************************/
     182             : 
     183          25 : const char *MMRRasterBand::GetUnitType()
     184             : 
     185             : {
     186          25 :     return m_osUnitType.c_str();
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*                            SetUnitType()                             */
     191             : /************************************************************************/
     192             : 
     193         210 : CPLErr MMRRasterBand::SetUnitType(const char *pszUnit)
     194             : 
     195             : {
     196         210 :     if (pszUnit == nullptr)
     197           0 :         m_osUnitType.clear();
     198             :     else
     199         210 :         m_osUnitType = pszUnit;
     200             : 
     201         210 :     return CE_None;
     202             : }
     203             : 
     204             : /************************************************************************/
     205             : /*                             IReadBlock()                             */
     206             : /************************************************************************/
     207             : 
     208         385 : CPLErr MMRRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     209             : 
     210             : {
     211         385 :     CPLErr eErr = CE_None;
     212             : 
     213         385 :     if (nBand < 1 || nBand > m_pfRel->GetNBands())
     214           0 :         return CE_Failure;
     215             : 
     216         385 :     MMRBand *pBand = m_pfRel->GetBand(nBand - 1);
     217         385 :     if (!pBand)
     218           0 :         return CE_Failure;
     219         770 :     eErr = pBand->GetRasterBlock(nBlockXOff, nBlockYOff, pImage,
     220         385 :                                  nBlockXSize * nBlockYSize *
     221         385 :                                      GDALGetDataTypeSizeBytes(eDataType));
     222             : 
     223         385 :     if (eErr == CE_None &&
     224         385 :         m_eMMRDataTypeMiraMon == MMDataType::DATATYPE_AND_COMPR_BIT)
     225             :     {
     226          16 :         GByte *pabyData = static_cast<GByte *>(pImage);
     227             : 
     228         144 :         for (int nIAccumulated = nBlockXSize * nBlockYSize - 1;
     229         144 :              nIAccumulated >= 0; nIAccumulated--)
     230             :         {
     231         128 :             if ((pabyData[nIAccumulated >> 3] & (1 << (nIAccumulated & 0x7))))
     232          64 :                 pabyData[nIAccumulated] = 1;
     233             :             else
     234          64 :                 pabyData[nIAccumulated] = 0;
     235             :         }
     236             :     }
     237             : 
     238         385 :     return eErr;
     239             : }
     240             : 
     241             : /************************************************************************/
     242             : /*                           GetColorTable()                            */
     243             : /************************************************************************/
     244             : 
     245         182 : GDALColorTable *MMRRasterBand::GetColorTable()
     246             : {
     247             :     // If user doesn't want the CT, it's skipped
     248         182 :     if (nRatOrCT != RAT_OR_CT::ALL && nRatOrCT != RAT_OR_CT::CT)
     249           2 :         return nullptr;
     250             : 
     251         180 :     if (m_bTriedLoadColorTable)
     252          63 :         return m_poCT.get();
     253             : 
     254         117 :     m_bTriedLoadColorTable = true;
     255             : 
     256         117 :     m_Palette = std::make_unique<MMRPalettes>(*m_pfRel, nBand);
     257             : 
     258         117 :     if (!m_Palette->IsValid())
     259             :     {
     260          26 :         m_Palette = nullptr;
     261          26 :         return nullptr;
     262             :     }
     263             : 
     264          91 :     m_poCT = std::make_unique<GDALColorTable>();
     265             : 
     266             :     /*
     267             :     * GDALPaletteInterp
     268             :     */
     269             : 
     270          91 :     if (CE_None != UpdateTableColorsFromPalette())
     271             :     {
     272             :         // No color table available. Perhaps some attribute table with the colors?
     273          10 :         m_poCT = nullptr;
     274          10 :         return m_poCT.get();
     275             :     }
     276             : 
     277          81 :     ConvertColorsFromPaletteToColorTable();
     278             : 
     279          81 :     return m_poCT.get();
     280             : }
     281             : 
     282             : /************************************************************************/
     283             : /*                       GetColorInterpretation()                       */
     284             : /************************************************************************/
     285             : 
     286          69 : GDALColorInterp MMRRasterBand::GetColorInterpretation()
     287             : {
     288          69 :     GDALColorTable *ct = GetColorTable();
     289             : 
     290          69 :     if (ct)
     291          46 :         return GCI_PaletteIndex;
     292             : 
     293          23 :     return GCI_GrayIndex;
     294             : }
     295             : 
     296             : /************************************************************************/
     297             : /*                           GetDefaultRAT()                            */
     298             : /************************************************************************/
     299             : 
     300          39 : GDALRasterAttributeTable *MMRRasterBand::GetDefaultRAT()
     301             : 
     302             : {
     303             :     // If user doesn't want the RAT, it's skipped
     304          39 :     if (nRatOrCT != RAT_OR_CT::ALL && nRatOrCT != RAT_OR_CT::RAT)
     305           1 :         return nullptr;
     306             : 
     307          38 :     if (m_poDefaultRAT != nullptr)
     308           0 :         return m_poDefaultRAT.get();
     309             : 
     310          38 :     m_poDefaultRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
     311             : 
     312          38 :     if (CE_None != FillRATFromPalette())
     313             :     {
     314           1 :         m_poDefaultRAT = nullptr;
     315             :     }
     316             : 
     317          38 :     return m_poDefaultRAT.get();
     318             : }
     319             : 
     320          38 : CPLErr MMRRasterBand::FillRATFromPalette()
     321             : 
     322             : {
     323          76 :     CPLString os_IndexJoin;
     324             : 
     325          38 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     326          38 :     if (poBand == nullptr)
     327           0 :         return CE_None;
     328             : 
     329          38 :     GetColorTable();
     330          38 :     if (poBand->GetShortRATName().empty() && !m_poCT)
     331             :     {
     332             :         // I don't have any associated attribute table but
     333             :         // perhaps I can create an attribute table with
     334             :         // the colors (if I have them and are not at the color table)
     335             :         // assigned to the pixels).
     336           6 :         if (CE_None != UpdateAttributeColorsFromPalette())
     337           0 :             return CE_Failure;
     338             : 
     339           6 :         return CE_None;
     340             :     }
     341             : 
     342             :     // Let's see the conditions to have a RAT
     343          64 :     CPLString osRELName, osDBFName, osAssociateRel;
     344          64 :     if (CE_None != GetRATName(osRELName, osDBFName, osAssociateRel) ||
     345          64 :         osDBFName.empty() || osAssociateRel.empty())
     346             :     {
     347           1 :         return CE_Failure;
     348             :     }
     349             : 
     350             :     // Let's create and fill the RAT
     351          31 :     if (CE_None != CreateRATFromDBF(osRELName, osDBFName, osAssociateRel))
     352           0 :         return CE_Failure;
     353             : 
     354          31 :     return CE_None;
     355             : }
     356             : 
     357           6 : CPLErr MMRRasterBand::UpdateAttributeColorsFromPalette()
     358             : 
     359             : {
     360             :     // If there is no palette, let's get one
     361           6 :     if (!m_Palette)
     362             :     {
     363           1 :         m_Palette = std::make_unique<MMRPalettes>(*m_pfRel, nBand);
     364             : 
     365           1 :         if (!m_Palette->IsValid())
     366             :         {
     367           1 :             m_Palette = nullptr;
     368           1 :             return CE_None;
     369             :         }
     370             :     }
     371             : 
     372           5 :     return FromPaletteToAttributeTable();
     373             : }
     374             : 
     375          31 : CPLErr MMRRasterBand::CreateRATFromDBF(const CPLString &osRELName,
     376             :                                        const CPLString &osDBFName,
     377             :                                        const CPLString &osAssociateRel)
     378             : {
     379             :     // If there is no palette, let's try to get one
     380             :     // and try to get a normal RAT.
     381          31 :     if (!m_Palette)
     382             :     {
     383           1 :         m_Palette = std::make_unique<MMRPalettes>(*m_pfRel, nBand);
     384             : 
     385           1 :         if (!m_Palette->IsValid() || !m_Palette->IsCategorical())
     386           1 :             m_Palette = nullptr;
     387             :     }
     388             : 
     389             :     struct MM_DATA_BASE_XP oAttributteTable;
     390          31 :     memset(&oAttributteTable, 0, sizeof(oAttributteTable));
     391             : 
     392          31 :     if (!osRELName.empty())
     393             :     {
     394          30 :         if (MM_ReadExtendedDBFHeaderFromFile(
     395          30 :                 osDBFName.c_str(), &oAttributteTable, osRELName.c_str()))
     396             :         {
     397           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     398             :                      "Error reading attribute table \"%s\".",
     399             :                      osDBFName.c_str());
     400           0 :             return CE_None;
     401             :         }
     402             :     }
     403             :     else
     404             :     {
     405           1 :         if (MM_ReadExtendedDBFHeaderFromFile(osDBFName.c_str(),
     406           1 :                                              &oAttributteTable, nullptr))
     407             :         {
     408           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     409             :                      "Error reading attribute table \"%s\".",
     410             :                      osDBFName.c_str());
     411           0 :             return CE_None;
     412             :         }
     413             :     }
     414             : 
     415             :     MM_EXT_DBF_N_FIELDS nIField;
     416          31 :     MM_EXT_DBF_N_FIELDS nFieldIndex = oAttributteTable.nFields;
     417          31 :     MM_EXT_DBF_N_FIELDS nCategIndex = oAttributteTable.nFields;
     418          31 :     for (nIField = 0; nIField < oAttributteTable.nFields; nIField++)
     419             :     {
     420          31 :         if (EQUAL(oAttributteTable.pField[nIField].FieldName, osAssociateRel))
     421             :         {
     422          31 :             nFieldIndex = nIField;
     423          31 :             if (nIField + 1 < oAttributteTable.nFields)
     424          31 :                 nCategIndex = nIField + 1;
     425           0 :             else if (nIField > 1)
     426           0 :                 nCategIndex = nIField - 1;
     427          31 :             break;
     428             :         }
     429             :     }
     430             : 
     431          31 :     if (nFieldIndex == oAttributteTable.nFields)
     432             :     {
     433           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid attribute table: \"%s\"",
     434             :                  oAttributteTable.szFileName);
     435           0 :         return CE_Failure;
     436             :     }
     437             : 
     438          31 :     if (oAttributteTable.pField[nFieldIndex].FieldType != 'N')
     439             :     {
     440           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     441             :                  "Invalid attribute table field: \"%s\"",
     442             :                  oAttributteTable.szFileName);
     443           0 :         return CE_Failure;
     444             :     }
     445             : 
     446             :     // 0 column: category value
     447          31 :     if (oAttributteTable.pField[nFieldIndex].DecimalsIfFloat)
     448             :     {
     449           0 :         if (CE_None != m_poDefaultRAT->CreateColumn(
     450           0 :                            oAttributteTable.pField[nFieldIndex].FieldName,
     451           0 :                            GFT_Real, GFU_MinMax))
     452           0 :             return CE_Failure;
     453             :     }
     454             :     else
     455             :     {
     456          62 :         if (CE_None != m_poDefaultRAT->CreateColumn(
     457          31 :                            oAttributteTable.pField[nFieldIndex].FieldName,
     458          31 :                            GFT_Integer, GFU_MinMax))
     459           0 :             return CE_Failure;
     460             :     }
     461             : 
     462             :     GDALRATFieldUsage eFieldUsage;
     463             :     GDALRATFieldType eFieldType;
     464             : 
     465         137 :     for (nIField = 0; nIField < oAttributteTable.nFields; nIField++)
     466             :     {
     467         106 :         if (nIField == nFieldIndex)
     468          31 :             continue;
     469             : 
     470          75 :         if (oAttributteTable.pField[nIField].FieldType == 'N')
     471             :         {
     472          29 :             eFieldUsage = GFU_MinMax;
     473          29 :             if (oAttributteTable.pField[nIField].DecimalsIfFloat)
     474          29 :                 eFieldType = GFT_Real;
     475             :             else
     476           0 :                 eFieldType = GFT_Integer;
     477             :         }
     478             :         else
     479             :         {
     480          46 :             eFieldUsage = GFU_Generic;
     481          46 :             eFieldType = GFT_String;
     482             :         }
     483          75 :         if (nIField == nCategIndex)
     484          31 :             eFieldUsage = GFU_Name;
     485             : 
     486         150 :         if (CE_None != m_poDefaultRAT->CreateColumn(
     487          75 :                            oAttributteTable.pField[nIField].FieldName,
     488          75 :                            eFieldType, eFieldUsage))
     489           0 :             return CE_Failure;
     490             :     }
     491             : 
     492          31 :     VSIFSeekL(oAttributteTable.pfDataBase,
     493          31 :               static_cast<vsi_l_offset>(oAttributteTable.FirstRecordOffset),
     494             :               SEEK_SET);
     495             : 
     496          31 :     MM_ACCUMULATED_BYTES_TYPE_DBF nBufferSize =
     497          31 :         oAttributteTable.BytesPerRecord + 1;
     498          31 :     char *pzsRecord = static_cast<char *>(VSI_CALLOC_VERBOSE(1, nBufferSize));
     499          31 :     if (!pzsRecord)
     500             :     {
     501           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     502             :                  "Out of memory allocating working buffer");
     503           0 :         VSIFCloseL(oAttributteTable.pfDataBase);
     504           0 :         MM_ReleaseMainFields(&oAttributteTable);
     505           0 :         return CE_Failure;
     506             :     }
     507             : 
     508          31 :     char *pszField = static_cast<char *>(VSI_CALLOC_VERBOSE(1, nBufferSize));
     509          31 :     if (!pszField)
     510             :     {
     511           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     512             :                  "Out of memory allocating working buffer");
     513           0 :         VSIFree(pzsRecord);
     514           0 :         VSIFCloseL(oAttributteTable.pfDataBase);
     515           0 :         MM_ReleaseMainFields(&oAttributteTable);
     516           0 :         return CE_Failure;
     517             :     }
     518             : 
     519          31 :     CPLErr eErr = CE_None;
     520         307 :     for (int nIRecord = 0;
     521         307 :          eErr == CE_None &&
     522         307 :          nIRecord < static_cast<int>(oAttributteTable.nRecords);
     523             :          nIRecord++)
     524             :     {
     525         552 :         if (oAttributteTable.BytesPerRecord !=
     526         276 :             VSIFReadL(pzsRecord, sizeof(unsigned char),
     527         276 :                       oAttributteTable.BytesPerRecord,
     528             :                       oAttributteTable.pfDataBase))
     529             :         {
     530           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     531             :                      "Invalid attribute table: \"%s\"", osDBFName.c_str());
     532             : 
     533           0 :             eErr = CE_Failure;
     534           0 :             break;
     535             :         }
     536             : 
     537             :         // Category index
     538         276 :         memcpy(pszField,
     539         276 :                pzsRecord +
     540         276 :                    oAttributteTable.pField[nFieldIndex].AccumulatedBytes,
     541         276 :                oAttributteTable.pField[nFieldIndex].BytesPerField);
     542         276 :         pszField[oAttributteTable.pField[nFieldIndex].BytesPerField] = '\0';
     543         276 :         CPLString osCatField = pszField;
     544             : 
     545             :         int nCatField;
     546         276 :         if (1 != sscanf(osCatField, "%d", &nCatField))
     547             :         {
     548           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     549             :                      "Invalid attribute table: \"%s\"", osDBFName.c_str());
     550             : 
     551           0 :             eErr = CE_Failure;
     552           0 :             break;
     553             :         }
     554         276 :         m_poDefaultRAT->SetRowCount(nCatField + 1);
     555         276 :         m_poDefaultRAT->SetValue(nCatField, 0, osCatField.c_str());
     556             : 
     557         276 :         int nIOrderedField = 1;
     558        1452 :         for (nIField = 0; nIField < oAttributteTable.nFields; nIField++)
     559             :         {
     560        1176 :             if (nIField == nFieldIndex)
     561         276 :                 continue;
     562             : 
     563             :             // Category value
     564         900 :             memcpy(pszField,
     565         900 :                    pzsRecord +
     566         900 :                        oAttributteTable.pField[nIField].AccumulatedBytes,
     567         900 :                    oAttributteTable.pField[nIField].BytesPerField);
     568         900 :             pszField[oAttributteTable.pField[nIField].BytesPerField] = '\0';
     569             : 
     570         900 :             if (oAttributteTable.CharSet == MM_JOC_CARAC_OEM850_DBASE)
     571          12 :                 MM_oemansi(pszField);
     572             : 
     573         900 :             CPLString osField = pszField;
     574         900 :             osField.Trim();
     575             : 
     576         900 :             if (oAttributteTable.CharSet != MM_JOC_CARAC_UTF8_DBF &&
     577         900 :                 oAttributteTable.pField[nIField].FieldType != 'N')
     578             :             {
     579             :                 // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
     580         636 :                 osField.Recode(CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
     581             :             }
     582             : 
     583         900 :             if (1 != sscanf(osCatField, "%d", &nCatField))
     584             :             {
     585           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     586             :                          "Invalid attribute table: \"%s\"", osDBFName.c_str());
     587             : 
     588           0 :                 eErr = CE_Failure;
     589           0 :                 break;
     590             :             }
     591         900 :             m_poDefaultRAT->SetRowCount(nCatField + 1);
     592        1800 :             if (CE_None != m_poDefaultRAT->SetValue(nCatField, nIOrderedField,
     593         900 :                                                     osField.c_str()))
     594             :             {
     595           0 :                 eErr = CE_Failure;
     596           0 :                 break;
     597             :             }
     598         900 :             m_poDefaultRAT->SetRowCount(nCatField + 1);
     599        1800 :             if (CE_None != m_poDefaultRAT->SetValue(nCatField, nIOrderedField,
     600         900 :                                                     osField.c_str()))
     601             :             {
     602           0 :                 eErr = CE_Failure;
     603           0 :                 break;
     604             :             }
     605         900 :             nIOrderedField++;
     606             :         }
     607         276 :         if (eErr == CE_Failure)
     608           0 :             break;
     609             :     }
     610             : 
     611          31 :     VSIFree(pszField);
     612          31 :     VSIFree(pzsRecord);
     613          31 :     VSIFCloseL(oAttributteTable.pfDataBase);
     614          31 :     MM_ReleaseMainFields(&oAttributteTable);
     615             : 
     616          31 :     return eErr;
     617             : }
     618             : 
     619          91 : CPLErr MMRRasterBand::UpdateTableColorsFromPalette()
     620             : 
     621             : {
     622          91 :     if (!m_Palette || !m_Palette->IsValid())
     623           0 :         return CE_Failure;
     624             : 
     625          91 :     if (m_Palette->IsConstantColor())
     626           3 :         return AssignUniformColorTable();
     627             : 
     628             :     CPLErr peErr;
     629          88 :     if (m_Palette->IsCategorical())
     630          74 :         peErr = FromPaletteToColorTableCategoricalMode();
     631             :     else
     632          14 :         peErr = FromPaletteToColorTableContinuousMode();
     633             : 
     634          88 :     return peErr;
     635             : }
     636             : 
     637           3 : CPLErr MMRRasterBand::AssignUniformColorTable()
     638             : 
     639             : {
     640           3 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     641           3 :     if (!poBand)
     642           0 :         return CE_Failure;
     643             : 
     644             :     int nNPossibleValues;
     645           3 :     double maxIndex = 0.0;
     646             : 
     647           3 :     if (poBand->BandHasNoData() && poBand->GetNoDataValue() < 0)
     648           1 :         return CE_Failure;
     649             : 
     650           2 :     if (poBand->GetVisuMaxSet() && poBand->GetVisuMax() < 0)
     651           0 :         return CE_Failure;
     652             : 
     653           4 :     if (poBand->BandHasNoData() &&
     654           2 :         static_cast<int>(poBand->GetNoDataValue()) < INT_MAX)
     655           2 :         maxIndex = poBand->GetNoDataValue() + 1;
     656             : 
     657           4 :     if (poBand->GetVisuMaxSet() &&
     658           2 :         static_cast<int>(poBand->GetVisuMax()) < INT_MAX)
     659           2 :         maxIndex = std::max(maxIndex, poBand->GetVisuMax() + 1);
     660             : 
     661           2 :     if (maxIndex != 0)
     662           2 :         nNPossibleValues = static_cast<int>(maxIndex);
     663             :     else
     664             :     {
     665             :         // Only for 1 or 2 bytes images
     666           0 :         if (m_eMMBytesPerPixel !=
     667           0 :                 MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE &&
     668           0 :             m_eMMBytesPerPixel !=
     669             :                 MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE)
     670             :         {
     671           0 :             return CE_None;
     672             :         }
     673             : 
     674           0 :         nNPossibleValues = 1 << (8 * static_cast<int>(m_eMMBytesPerPixel));
     675             :     }
     676             : 
     677           2 :     if (nNPossibleValues <= 0)
     678           0 :         return CE_Failure;
     679             : 
     680          10 :     for (int iColumn = 0; iColumn < 4; iColumn++)
     681             :     {
     682             :         try
     683             :         {
     684           8 :             m_aadfPCT[iColumn].resize(nNPossibleValues);
     685             :         }
     686           0 :         catch (std::bad_alloc &e)
     687             :         {
     688           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     689           0 :             return CE_Failure;
     690             :         }
     691             :     }
     692             : 
     693          14 :     for (int nITableColor = 0; nITableColor < nNPossibleValues; nITableColor++)
     694             :     {
     695          12 :         if (poBand->BandHasNoData() && nITableColor == poBand->GetNoDataValue())
     696             :         {
     697           2 :             m_aadfPCT[0][nITableColor] = 0;
     698           2 :             m_aadfPCT[1][nITableColor] = 0;
     699           2 :             m_aadfPCT[2][nITableColor] = 0;
     700           2 :             m_aadfPCT[3][nITableColor] = 0;
     701             :         }
     702             :         else
     703             :         {
     704             :             // Before the minimum, we apply the color of the first
     705             :             // element (as a placeholder).
     706          10 :             m_aadfPCT[0][nITableColor] = m_Palette->GetConstantColorRGB().c1;
     707          10 :             m_aadfPCT[1][nITableColor] = m_Palette->GetConstantColorRGB().c2;
     708          10 :             m_aadfPCT[2][nITableColor] = m_Palette->GetConstantColorRGB().c3;
     709          10 :             m_aadfPCT[3][nITableColor] = 255;
     710             :         }
     711             :     }
     712             : 
     713           2 :     return CE_None;
     714             : }
     715             : 
     716             : // Converts palette Colors to Colors of pixels
     717          74 : CPLErr MMRRasterBand::FromPaletteToColorTableCategoricalMode()
     718             : 
     719             : {
     720          74 :     if (!m_Palette)
     721           0 :         return CE_Failure;
     722             : 
     723          74 :     if (!m_Palette->IsCategorical())
     724           0 :         return CE_Failure;
     725             : 
     726             :     // If the palette is not loaded, then, ignore the conversion silently
     727          74 :     if (m_Palette->GetSizeOfPaletteColors() == 0)
     728           1 :         return CE_Failure;
     729             : 
     730          73 :     if (m_Palette->GetColorScaling() == ColorTreatment::DEFAULT_SCALING)
     731           0 :         m_Palette->SetColorScaling(ColorTreatment::DIRECT_ASSIGNATION);
     732          73 :     else if (m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
     733           0 :         return CE_Failure;
     734             : 
     735             :     // Getting number of color in the palette
     736          73 :     int nNPaletteColors = m_Palette->GetSizeOfPaletteColors();
     737             :     int nNPossibleValues;
     738             : 
     739          73 :     if (m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_BYTE &&
     740          54 :         m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_BYTE_RLE &&
     741          34 :         m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_UINTEGER &&
     742          26 :         m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE)
     743             :     {
     744             :         // Rare case where its a not byte or uinteger img file
     745             :         // but it has a categorical palettte.
     746          18 :         nNPossibleValues = nNPaletteColors;
     747             :     }
     748             :     else
     749             :     {
     750             :         // To relax Coverity Scan (CID 1620826)
     751          55 :         MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     752          55 :         if (!poBand)
     753           0 :             return CE_Failure;
     754             : 
     755          55 :         if (m_Palette->IsAutomatic() && poBand->GetMaxSet())
     756             :         {
     757             :             // In that case (byte, uint) we can limit the number
     758             :             // of colours at the maximum value that the band has.
     759          28 :             if (static_cast<int>(poBand->GetMax()) == INT_MAX)
     760           0 :                 return CE_Failure;
     761          28 :             nNPossibleValues = static_cast<int>(poBand->GetMax()) + 1;
     762             : 
     763             :             // Oss-fuzz issue: 484932882
     764          28 :             if (nNPossibleValues <= 0 || nNPossibleValues >= 65536)
     765           0 :                 return CE_Failure;
     766             :         }
     767             :         else
     768             :         {
     769          27 :             CPLAssert(static_cast<int>(m_eMMBytesPerPixel) > 0);
     770          27 :             nNPossibleValues = 1 << (8 * static_cast<int>(m_eMMBytesPerPixel));
     771             :         }
     772             :     }
     773             : 
     774         365 :     for (int iColumn = 0; iColumn < 4; iColumn++)
     775             :     {
     776             :         try
     777             :         {
     778         292 :             m_aadfPCT[iColumn].resize(nNPossibleValues);
     779             :         }
     780           0 :         catch (std::bad_alloc &e)
     781             :         {
     782           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     783           0 :             return CE_Failure;
     784             :         }
     785             :     }
     786             : 
     787             :     // No more colors than needed.
     788          73 :     if (nNPaletteColors > nNPossibleValues)
     789          29 :         nNPaletteColors = nNPossibleValues;
     790             : 
     791          73 :     int nIPaletteColor = 0;
     792        5417 :     for (nIPaletteColor = 0; nIPaletteColor < nNPaletteColors; nIPaletteColor++)
     793             :     {
     794        5344 :         m_aadfPCT[0][nIPaletteColor] =
     795        5344 :             m_Palette->GetPaletteColorsValue(0, nIPaletteColor);
     796        5344 :         m_aadfPCT[1][nIPaletteColor] =
     797        5344 :             m_Palette->GetPaletteColorsValue(1, nIPaletteColor);
     798        5344 :         m_aadfPCT[2][nIPaletteColor] =
     799        5344 :             m_Palette->GetPaletteColorsValue(2, nIPaletteColor);
     800        5344 :         m_aadfPCT[3][nIPaletteColor] =
     801        5344 :             m_Palette->GetPaletteColorsValue(3, nIPaletteColor);
     802             :     }
     803             : 
     804             :     // Rest of colors
     805        6165 :     for (; nIPaletteColor < nNPossibleValues; nIPaletteColor++)
     806             :     {
     807        6092 :         m_aadfPCT[0][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c1;
     808        6092 :         m_aadfPCT[1][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c2;
     809        6092 :         m_aadfPCT[2][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c3;
     810        6092 :         m_aadfPCT[3][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c4;
     811             :     }
     812             : 
     813          73 :     return CE_None;
     814             : }
     815             : 
     816             : // Converts paletteColors to Colors of pixels for the Color Table
     817          14 : CPLErr MMRRasterBand::FromPaletteToColorTableContinuousMode()
     818             : 
     819             : {
     820          14 :     if (!m_Palette)
     821           0 :         return CE_Failure;
     822             : 
     823          14 :     if (m_Palette->IsCategorical())
     824           0 :         return CE_Failure;
     825             : 
     826             :     // TODO: more types of scaling
     827          20 :     if (m_Palette->GetColorScaling() != ColorTreatment::LINEAR_SCALING &&
     828           6 :         m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
     829           0 :         return CE_Failure;
     830             : 
     831          14 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     832          14 :     if (!poBand)
     833           0 :         return CE_Failure;
     834             : 
     835          14 :     bool bAcceptPalette = false;
     836          39 :     if ((m_eMMRDataTypeMiraMon == MMDataType::DATATYPE_AND_COMPR_BYTE ||
     837          17 :          m_eMMRDataTypeMiraMon == MMDataType::DATATYPE_AND_COMPR_BYTE_RLE) &&
     838           3 :         (m_Palette->GetColorScaling() == ColorTreatment::LINEAR_SCALING ||
     839           0 :          m_Palette->GetColorScaling() == ColorTreatment::DIRECT_ASSIGNATION))
     840           3 :         bAcceptPalette = true;
     841          22 :     else if ((m_eMMRDataTypeMiraMon ==
     842           7 :                   MMDataType::DATATYPE_AND_COMPR_UINTEGER ||
     843           7 :               m_eMMRDataTypeMiraMon ==
     844          22 :                   MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE) &&
     845           5 :              m_Palette->GetColorScaling() == ColorTreatment::DIRECT_ASSIGNATION)
     846           3 :         bAcceptPalette = true;
     847             : 
     848          14 :     if (!bAcceptPalette)
     849           8 :         return CE_Failure;  // Attribute table
     850             : 
     851             :     // Some necessary information
     852           6 :     if (!poBand->GetVisuMinSet() || !poBand->GetVisuMaxSet())
     853           0 :         return CE_Failure;
     854             : 
     855             :     // To relax Coverity Scan (CID 1620843)
     856           6 :     CPLAssert(static_cast<int>(m_eMMBytesPerPixel) > 0);
     857             : 
     858           6 :     const int nNPossibleValues = 1
     859           6 :                                  << (8 * static_cast<int>(m_eMMBytesPerPixel));
     860          30 :     for (int iColumn = 0; iColumn < 4; iColumn++)
     861             :     {
     862             :         try
     863             :         {
     864          24 :             m_aadfPCT[iColumn].resize(nNPossibleValues);
     865             :         }
     866           0 :         catch (std::bad_alloc &e)
     867             :         {
     868           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     869           0 :             return CE_Failure;
     870             :         }
     871             :     }
     872             : 
     873           6 :     if (static_cast<int>(m_eMMBytesPerPixel) > 2 &&
     874           0 :         m_Palette->GetNumberOfColors() < nNPossibleValues)
     875           0 :         return CE_Failure;
     876             : 
     877           6 :     if (m_Palette->GetNumberOfColors() < 1)
     878           0 :         return CE_Failure;
     879             : 
     880             :     int nFirstValidPaletteIndex;
     881             :     unsigned short nIndexColor;
     882           6 :     double dfSlope = 1, dfIntercept = 0;
     883             : 
     884           6 :     if (m_Palette->HasNodata() && m_Palette->GetNoDataPaletteIndex() == 0)
     885           0 :         nFirstValidPaletteIndex = 1;
     886             :     else
     887           6 :         nFirstValidPaletteIndex = 0;
     888             : 
     889           6 :     int nIPaletteColorNoData = 0;
     890           9 :     if (static_cast<int>(m_eMMBytesPerPixel) == 2 ||
     891           3 :         m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
     892             :     {
     893             :         // A scaling is applied between the minimum and maximum display values.
     894           6 :         dfSlope = (static_cast<double>(m_Palette->GetNumberOfColors()) - 1) /
     895           6 :                   (poBand->GetVisuMax() - poBand->GetVisuMin());
     896             : 
     897           6 :         dfIntercept = -dfSlope * poBand->GetVisuMin();
     898             : 
     899           6 :         if (poBand->BandHasNoData())
     900             :         {
     901           6 :             if (m_Palette->GetNoDataPaletteIndex() ==
     902           3 :                 m_Palette->GetNumberOfColors())
     903           3 :                 nIPaletteColorNoData = nNPossibleValues - 1;
     904             :         }
     905             :     }
     906             : 
     907      197382 :     for (int nIPaletteColor = 0; nIPaletteColor < nNPossibleValues;
     908             :          nIPaletteColor++)
     909             :     {
     910      197376 :         if (poBand->BandHasNoData() && nIPaletteColor == nIPaletteColorNoData)
     911             :         {
     912           3 :             if (m_Palette->HasNodata())
     913           2 :                 AssignRGBColor(nIPaletteColor,
     914             :                                m_Palette->GetNoDataPaletteIndex());
     915             :             else
     916           1 :                 AssignRGBColorDirectly(nIPaletteColor, 255);
     917             :         }
     918             :         else
     919             :         {
     920      197373 :             if (nIPaletteColor < static_cast<int>(poBand->GetVisuMin()))
     921             :             {
     922             :                 // Before the minimum, we apply the color of the first
     923             :                 // element (as a placeholder).
     924           0 :                 AssignRGBColor(nIPaletteColor, 0);
     925             :             }
     926      197373 :             else if (nIPaletteColor <= static_cast<int>(poBand->GetVisuMax()))
     927             :             {
     928             :                 // Between the minimum and maximum, we apply the value
     929             :                 // read from the table.
     930          50 :                 if (static_cast<int>(m_eMMBytesPerPixel) < 2 ||
     931          16 :                     m_Palette->GetColorScaling() ==
     932             :                         ColorTreatment::DIRECT_ASSIGNATION)
     933             :                 {
     934             :                     // The value is applied directly.
     935          34 :                     AssignRGBColor(nIPaletteColor, nFirstValidPaletteIndex);
     936          34 :                     nFirstValidPaletteIndex++;
     937             :                 }
     938             :                 else
     939             :                 {
     940             :                     // The value is applied according to the scaling.
     941           0 :                     nIndexColor = static_cast<unsigned short>(
     942           0 :                         dfSlope * nIPaletteColor + dfIntercept);
     943           0 :                     if (nIndexColor > m_Palette->GetNumberOfColors())
     944           0 :                         nIndexColor = static_cast<unsigned short>(
     945           0 :                             m_Palette->GetNumberOfColors());
     946           0 :                     AssignRGBColor(nIPaletteColor, nIndexColor);
     947             :                 }
     948             :             }
     949             :             else
     950             :             {
     951             :                 // After the maximum, we apply the value of the last
     952             :                 // element (as a placeholder).
     953      197339 :                 AssignRGBColor(nIPaletteColor,
     954      197339 :                                m_Palette->GetNumberOfColors() - 1);
     955             :             }
     956             :         }
     957             :     }
     958             : 
     959           6 :     return CE_None;
     960             : }
     961             : 
     962          32 : CPLErr MMRRasterBand::GetRATName(CPLString &osRELName, CPLString &osDBFName,
     963             :                                  CPLString &osAssociateREL)
     964             : {
     965          32 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
     966          32 :     if (!poBand)
     967           0 :         return CE_Failure;
     968             : 
     969          32 :     if (poBand->GetShortRATName().empty())
     970           1 :         return CE_None;  // There is no RAT
     971             : 
     972          62 :     CPLString osExtension = CPLGetExtensionSafe(poBand->GetShortRATName());
     973          31 :     if (osExtension.tolower() == "rel")
     974             :     {
     975             :         // Get path relative to REL file
     976          60 :         osRELName = CPLFormFilenameSafe(
     977          60 :             CPLGetPathSafe(m_pfRel->GetRELNameChar()).c_str(),
     978          60 :             poBand->GetShortRATName(), "");
     979             : 
     980             :         // Getting information from the associated REL
     981          60 :         MMRRel localRel(osRELName, false);
     982          60 :         CPLString osShortDBFName;
     983             : 
     984          30 :         if (!localRel.GetMetadataValue(SECTION_TAULA_PRINCIPAL, KEY_NomFitxer,
     985          60 :                                        osShortDBFName) ||
     986          30 :             osShortDBFName.empty())
     987             :         {
     988           0 :             osRELName = "";
     989           0 :             return CE_Failure;
     990             :         }
     991             : 
     992             :         // Get path relative to REL file
     993          60 :         osDBFName = CPLFormFilenameSafe(
     994          60 :             CPLGetPathSafe(localRel.GetRELNameChar()).c_str(), osShortDBFName,
     995          30 :             "");
     996             : 
     997          30 :         if (!localRel.GetMetadataValue(SECTION_TAULA_PRINCIPAL, "AssociatRel",
     998          60 :                                        osAssociateREL) ||
     999          30 :             osAssociateREL.empty())
    1000             :         {
    1001           0 :             osRELName = "";
    1002           0 :             return CE_Failure;
    1003             :         }
    1004             : 
    1005          60 :         CPLString osSection = SECTION_TAULA_PRINCIPAL;
    1006          30 :         osSection.append(":");
    1007          30 :         osSection.append(osAssociateREL);
    1008             : 
    1009          60 :         CPLString osTactVar;
    1010             : 
    1011          30 :         if (localRel.GetMetadataValue(osSection, KEY_TractamentVariable,
    1012          60 :                                       osTactVar) &&
    1013          30 :             osTactVar == "Categoric")
    1014          30 :             m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
    1015             :         else
    1016             :         {
    1017           0 :             osRELName = "";
    1018           0 :             return CE_Failure;
    1019             :         }
    1020             : 
    1021          30 :         return CE_None;
    1022             :     }
    1023             : 
    1024           1 :     osExtension = CPLGetExtensionSafe(poBand->GetShortRATName());
    1025           1 :     if (osExtension.tolower() == "dbf")
    1026             :     {
    1027           1 :         if (CPLIsFilenameRelative(poBand->GetShortRATName()))
    1028             :         {
    1029             :             // Get path relative to REL file
    1030           2 :             osDBFName = CPLFormFilenameSafe(
    1031           2 :                 CPLGetPathSafe(m_pfRel->GetRELNameChar()).c_str(),
    1032           2 :                 poBand->GetShortRATName(), "");
    1033             :         }
    1034             :         else
    1035           0 :             osDBFName = poBand->GetShortRATName();
    1036             : 
    1037           1 :         osAssociateREL = poBand->GetAssociateREL();
    1038           1 :         if (osAssociateREL.empty())
    1039             :         {
    1040           0 :             osRELName = "";
    1041           0 :             osDBFName = "";
    1042           0 :             return CE_Failure;
    1043             :         }
    1044           1 :         m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
    1045           1 :         return CE_None;
    1046             :     }
    1047             : 
    1048           0 :     osRELName = "";
    1049           0 :     osDBFName = "";
    1050           0 :     osAssociateREL = "";
    1051           0 :     return CE_Failure;
    1052             : }
    1053             : 
    1054             : // Converts paletteColors to Colors of pixels in the attribute table
    1055           5 : CPLErr MMRRasterBand::FromPaletteToAttributeTable()
    1056             : 
    1057             : {
    1058           5 :     if (!m_Palette)
    1059           0 :         return CE_None;
    1060             : 
    1061             :     // TODO: more types of scaling
    1062           7 :     if (m_Palette->GetColorScaling() != ColorTreatment::LINEAR_SCALING &&
    1063           2 :         m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
    1064           0 :         return CE_Failure;
    1065             : 
    1066           5 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
    1067           5 :     if (!poBand)
    1068           0 :         return CE_Failure;
    1069             : 
    1070           5 :     if (m_Palette->IsConstantColor())
    1071           1 :         return FromPaletteToAttributeTableConstant();
    1072             : 
    1073           4 :     if (m_Palette->GetNumberOfColors() <= 0)
    1074           0 :         return CE_Failure;
    1075             : 
    1076           4 :     if (m_Palette->GetColorScaling() == ColorTreatment::DIRECT_ASSIGNATION)
    1077           1 :         return FromPaletteToAttributeTableDirectAssig();
    1078             : 
    1079             :     // A scaling is applied between the minimum and maximum display values.
    1080           3 :     return FromPaletteToAttributeTableLinear();
    1081             : }
    1082             : 
    1083           1 : CPLErr MMRRasterBand::FromPaletteToAttributeTableConstant()
    1084             : {
    1085           1 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
    1086           1 :     if (!poBand)
    1087           0 :         return CE_Failure;
    1088             : 
    1089             :     // Some necessary information
    1090           1 :     if (!poBand->GetVisuMinSet() || !poBand->GetVisuMaxSet())
    1091           0 :         return CE_Failure;
    1092             : 
    1093           1 :     m_poDefaultRAT->CreateColumn("MIN", GFT_Real, GFU_Min);
    1094           1 :     m_poDefaultRAT->CreateColumn("MAX", GFT_Real, GFU_Max);
    1095           1 :     m_poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
    1096           1 :     m_poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
    1097           1 :     m_poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
    1098             : 
    1099           1 :     m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
    1100             : 
    1101           1 :     int nRow = 0;
    1102           1 :     if (poBand->BandHasNoData())
    1103             :     {
    1104           1 :         m_poDefaultRAT->SetRowCount(2);
    1105             : 
    1106           1 :         m_poDefaultRAT->SetValue(0, 0, poBand->GetNoDataValue());
    1107           1 :         m_poDefaultRAT->SetValue(0, 1, poBand->GetNoDataValue());
    1108           1 :         m_poDefaultRAT->SetValue(0, 2, m_Palette->GetNoDataDefaultColor().c1);
    1109           1 :         m_poDefaultRAT->SetValue(0, 3, m_Palette->GetNoDataDefaultColor().c2);
    1110           1 :         m_poDefaultRAT->SetValue(0, 4, m_Palette->GetNoDataDefaultColor().c3);
    1111           1 :         nRow++;
    1112             :     }
    1113             :     else
    1114           0 :         m_poDefaultRAT->SetRowCount(1);
    1115             : 
    1116             :     // Sets the constant color from min to max
    1117           1 :     m_poDefaultRAT->SetValue(nRow, 0, poBand->GetVisuMin());
    1118           1 :     m_poDefaultRAT->SetValue(nRow, 1, poBand->GetVisuMax());
    1119           1 :     m_poDefaultRAT->SetValue(nRow, 2, m_Palette->GetConstantColorRGB().c1);
    1120           1 :     m_poDefaultRAT->SetValue(nRow, 3, m_Palette->GetConstantColorRGB().c2);
    1121           1 :     m_poDefaultRAT->SetValue(nRow, 4, m_Palette->GetConstantColorRGB().c3);
    1122             : 
    1123           1 :     return CE_None;
    1124             : }
    1125             : 
    1126           1 : CPLErr MMRRasterBand::FromPaletteToAttributeTableDirectAssig()
    1127             : {
    1128           1 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
    1129           1 :     if (!poBand)
    1130           0 :         return CE_Failure;
    1131             : 
    1132           1 :     if (!m_Palette)
    1133           0 :         return CE_Failure;
    1134             : 
    1135           1 :     if (m_Palette->GetNumberOfColors() <= 0)
    1136           0 :         return CE_Failure;
    1137             : 
    1138           1 :     m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
    1139             : 
    1140           1 :     m_poDefaultRAT->CreateColumn("MIN_MAX", GFT_Real, GFU_MinMax);
    1141           1 :     m_poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
    1142           1 :     m_poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
    1143           1 :     m_poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
    1144             : 
    1145           2 :     m_poDefaultRAT->SetRowCount(static_cast<int>(
    1146           1 :         m_Palette->GetNumberOfColorsIncludingNodata()));  // +1 for last element
    1147             : 
    1148             :     // Nodata color assignation
    1149           1 :     int nIRow = 0;
    1150           1 :     if (poBand->BandHasNoData() && m_Palette->HasNodata())
    1151             :     {
    1152           0 :         m_poDefaultRAT->SetValue(nIRow, 0, poBand->GetNoDataValue());
    1153           0 :         m_poDefaultRAT->SetValue(nIRow, 1,
    1154             :                                  m_Palette->GetPaletteColorsValue(
    1155           0 :                                      0, m_Palette->GetNoDataPaletteIndex()));
    1156           0 :         m_poDefaultRAT->SetValue(nIRow, 2,
    1157             :                                  m_Palette->GetPaletteColorsValue(
    1158           0 :                                      1, m_Palette->GetNoDataPaletteIndex()));
    1159           0 :         m_poDefaultRAT->SetValue(nIRow, 3,
    1160             :                                  m_Palette->GetPaletteColorsValue(
    1161           0 :                                      2, m_Palette->GetNoDataPaletteIndex()));
    1162           0 :         nIRow++;
    1163             :     }
    1164             : 
    1165           1 :     int nIPaletteColor = 0;
    1166           7 :     for (; nIPaletteColor < m_Palette->GetNumberOfColors(); nIPaletteColor++)
    1167             :     {
    1168           6 :         if (nIPaletteColor == m_Palette->GetNoDataPaletteIndex())
    1169           0 :             continue;
    1170             : 
    1171           6 :         m_poDefaultRAT->SetValue(nIRow, 0, nIPaletteColor);
    1172             : 
    1173          12 :         m_poDefaultRAT->SetValue(
    1174           6 :             nIRow, 1, m_Palette->GetPaletteColorsValue(0, nIPaletteColor));
    1175          12 :         m_poDefaultRAT->SetValue(
    1176           6 :             nIRow, 2, m_Palette->GetPaletteColorsValue(1, nIPaletteColor));
    1177          12 :         m_poDefaultRAT->SetValue(
    1178           6 :             nIRow, 3, m_Palette->GetPaletteColorsValue(2, nIPaletteColor));
    1179             : 
    1180           6 :         nIRow++;
    1181             :     }
    1182             : 
    1183           1 :     return CE_None;
    1184             : }
    1185             : 
    1186           3 : CPLErr MMRRasterBand::FromPaletteToAttributeTableLinear()
    1187             : {
    1188           3 :     MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
    1189           3 :     if (!poBand)
    1190           0 :         return CE_Failure;
    1191             : 
    1192           3 :     if (!m_Palette)
    1193           0 :         return CE_Failure;
    1194             : 
    1195           3 :     if (m_Palette->GetNumberOfColors() <= 0)
    1196           0 :         return CE_Failure;
    1197             : 
    1198             :     // Some necessary information
    1199           3 :     if (!poBand->GetVisuMinSet() || !poBand->GetVisuMaxSet())
    1200           0 :         return CE_Failure;
    1201             : 
    1202           3 :     m_poDefaultRAT->SetTableType(GRTT_ATHEMATIC);
    1203           3 :     m_poDefaultRAT->CreateColumn("MIN", GFT_Real, GFU_Min);
    1204           3 :     m_poDefaultRAT->CreateColumn("MAX", GFT_Real, GFU_Max);
    1205           3 :     m_poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
    1206           3 :     m_poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
    1207           3 :     m_poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
    1208             : 
    1209           6 :     m_poDefaultRAT->SetRowCount(m_Palette->GetNumberOfColorsIncludingNodata() +
    1210           3 :                                 1);  // +1 for last element
    1211             : 
    1212             :     // Nodata color assignation
    1213           3 :     int nIRow = 0;
    1214           3 :     if (poBand->BandHasNoData() && m_Palette->HasNodata())
    1215             :     {
    1216           2 :         m_poDefaultRAT->SetValue(nIRow, 0, poBand->GetNoDataValue());
    1217           2 :         m_poDefaultRAT->SetValue(nIRow, 1, poBand->GetNoDataValue());
    1218           4 :         m_poDefaultRAT->SetValue(nIRow, 2,
    1219             :                                  m_Palette->GetPaletteColorsValue(
    1220           2 :                                      0, m_Palette->GetNoDataPaletteIndex()));
    1221           4 :         m_poDefaultRAT->SetValue(nIRow, 3,
    1222             :                                  m_Palette->GetPaletteColorsValue(
    1223           2 :                                      1, m_Palette->GetNoDataPaletteIndex()));
    1224           4 :         m_poDefaultRAT->SetValue(nIRow, 4,
    1225             :                                  m_Palette->GetPaletteColorsValue(
    1226           2 :                                      2, m_Palette->GetNoDataPaletteIndex()));
    1227           2 :         nIRow++;
    1228             :     }
    1229             : 
    1230             :     double dfInterval =
    1231           3 :         (poBand->GetVisuMax() - poBand->GetVisuMin()) /
    1232           3 :         (static_cast<double>(m_Palette->GetNumberOfColors()) + 1);
    1233             : 
    1234           3 :     int nIPaletteColorNoData = 0;
    1235           3 :     if (poBand->BandHasNoData())
    1236             :     {
    1237           4 :         if (m_Palette->GetNoDataPaletteIndex() ==
    1238           2 :             m_Palette->GetNumberOfColors())
    1239             :             nIPaletteColorNoData =
    1240           2 :                 m_Palette->GetNumberOfColorsIncludingNodata();
    1241             :     }
    1242             : 
    1243           3 :     bool bFirstIteration = true;
    1244           3 :     int nIPaletteColor = 0;
    1245         519 :     for (; nIPaletteColor < m_Palette->GetNumberOfColors() - 1;
    1246             :          nIPaletteColor++)
    1247             :     {
    1248         516 :         if (poBand->BandHasNoData() && m_Palette->HasNodata() &&
    1249             :             nIPaletteColor == nIPaletteColorNoData)
    1250           0 :             continue;
    1251         516 :         if (bFirstIteration)
    1252             :         {
    1253           3 :             m_poDefaultRAT->SetValue(
    1254           3 :                 nIRow, 0, poBand->GetVisuMin() + dfInterval * nIPaletteColor);
    1255             :         }
    1256             :         else
    1257             :         {
    1258         513 :             if (IsInteger())
    1259             :             {
    1260         260 :                 m_poDefaultRAT->SetValue(
    1261             :                     nIRow, 0,
    1262         260 :                     ceil(poBand->GetVisuMin() + dfInterval * nIPaletteColor));
    1263             :             }
    1264             :             else
    1265             :             {
    1266         253 :                 m_poDefaultRAT->SetValue(nIRow, 0,
    1267         253 :                                          poBand->GetVisuMin() +
    1268         253 :                                              dfInterval * nIPaletteColor);
    1269             :             }
    1270             :         }
    1271         516 :         bFirstIteration = false;
    1272             : 
    1273         516 :         if (IsInteger())
    1274             :         {
    1275         262 :             m_poDefaultRAT->SetValue(
    1276             :                 nIRow, 1,
    1277         262 :                 ceil(poBand->GetVisuMin() +
    1278         262 :                      dfInterval * (static_cast<double>(nIPaletteColor) + 1)));
    1279             :         }
    1280             :         else
    1281             :         {
    1282         254 :             m_poDefaultRAT->SetValue(
    1283             :                 nIRow, 1,
    1284         254 :                 poBand->GetVisuMin() +
    1285         254 :                     dfInterval * (static_cast<double>(nIPaletteColor) + 1));
    1286             :         }
    1287             : 
    1288        1032 :         m_poDefaultRAT->SetValue(
    1289         516 :             nIRow, 2, m_Palette->GetPaletteColorsValue(0, nIPaletteColor));
    1290        1032 :         m_poDefaultRAT->SetValue(
    1291         516 :             nIRow, 3, m_Palette->GetPaletteColorsValue(1, nIPaletteColor));
    1292        1032 :         m_poDefaultRAT->SetValue(
    1293         516 :             nIRow, 4, m_Palette->GetPaletteColorsValue(2, nIPaletteColor));
    1294             : 
    1295         516 :         nIRow++;
    1296             :     }
    1297             : 
    1298             :     // Last interval
    1299           3 :     if (IsInteger())
    1300             :     {
    1301           2 :         m_poDefaultRAT->SetValue(
    1302             :             nIRow, 0,
    1303             :             ceil(
    1304           2 :                 poBand->GetVisuMin() +
    1305           2 :                 dfInterval *
    1306           2 :                     (static_cast<double>(m_Palette->GetNumberOfColors()) - 1)));
    1307             :     }
    1308             :     else
    1309             :     {
    1310           1 :         m_poDefaultRAT->SetValue(
    1311             :             nIRow, 0,
    1312           1 :             poBand->GetVisuMin() +
    1313           1 :                 dfInterval *
    1314           1 :                     (static_cast<double>(m_Palette->GetNumberOfColors()) - 1));
    1315             :     }
    1316           3 :     m_poDefaultRAT->SetValue(nIRow, 1, poBand->GetVisuMax());
    1317           6 :     m_poDefaultRAT->SetValue(
    1318           3 :         nIRow, 2, m_Palette->GetPaletteColorsValue(0, nIPaletteColor - 1));
    1319           6 :     m_poDefaultRAT->SetValue(
    1320           3 :         nIRow, 3, m_Palette->GetPaletteColorsValue(1, nIPaletteColor - 1));
    1321           6 :     m_poDefaultRAT->SetValue(
    1322           3 :         nIRow, 4, m_Palette->GetPaletteColorsValue(2, nIPaletteColor - 1));
    1323             : 
    1324           3 :     nIRow++;
    1325             : 
    1326             :     // Last value
    1327           3 :     m_poDefaultRAT->SetValue(nIRow, 0, poBand->GetVisuMax());
    1328           3 :     m_poDefaultRAT->SetValue(nIRow, 1, poBand->GetVisuMax());
    1329           6 :     m_poDefaultRAT->SetValue(
    1330           3 :         nIRow, 2, m_Palette->GetPaletteColorsValue(0, nIPaletteColor - 1));
    1331           6 :     m_poDefaultRAT->SetValue(
    1332           3 :         nIRow, 3, m_Palette->GetPaletteColorsValue(1, nIPaletteColor - 1));
    1333           6 :     m_poDefaultRAT->SetValue(
    1334           3 :         nIRow, 4, m_Palette->GetPaletteColorsValue(2, nIPaletteColor - 1));
    1335             : 
    1336           3 :     return CE_None;
    1337             : }
    1338             : 
    1339          81 : void MMRRasterBand::ConvertColorsFromPaletteToColorTable()
    1340             : {
    1341          81 :     int nColors = static_cast<int>(GetPCT_Red().size());
    1342             : 
    1343          81 :     if (nColors > 0)
    1344             :     {
    1345      208649 :         for (int iColor = 0; iColor < nColors; iColor++)
    1346             :         {
    1347             :             GDALColorEntry sEntry = {
    1348      208569 :                 static_cast<short int>(GetPCT_Red()[iColor]),
    1349      208569 :                 static_cast<short int>(GetPCT_Green()[iColor]),
    1350      208569 :                 static_cast<short int>(GetPCT_Blue()[iColor]),
    1351      625707 :                 static_cast<short int>(GetPCT_Alpha()[iColor])};
    1352             : 
    1353      208569 :             if ((sEntry.c1 < 0 || sEntry.c1 > 255) ||
    1354      208568 :                 (sEntry.c2 < 0 || sEntry.c2 > 255) ||
    1355      208568 :                 (sEntry.c3 < 0 || sEntry.c3 > 255) ||
    1356      208568 :                 (sEntry.c4 < 0 || sEntry.c4 > 255))
    1357             :             {
    1358           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1359             :                          "Color table entry appears to be corrupt, skipping "
    1360             :                          "the rest. ");
    1361           1 :                 break;
    1362             :             }
    1363             : 
    1364      208568 :             m_poCT->SetColorEntry(iColor, &sEntry);
    1365             :         }
    1366             :     }
    1367          81 : }
    1368             : 
    1369      197375 : void MMRRasterBand::AssignRGBColor(int nIndexDstCT, int nIndexSrcPalette)
    1370             : {
    1371      197375 :     m_aadfPCT[0][nIndexDstCT] =
    1372      197375 :         m_Palette->GetPaletteColorsValue(0, nIndexSrcPalette);
    1373      197375 :     m_aadfPCT[1][nIndexDstCT] =
    1374      197375 :         m_Palette->GetPaletteColorsValue(1, nIndexSrcPalette);
    1375      197375 :     m_aadfPCT[2][nIndexDstCT] =
    1376      197375 :         m_Palette->GetPaletteColorsValue(2, nIndexSrcPalette);
    1377      197375 :     m_aadfPCT[3][nIndexDstCT] =
    1378      197375 :         m_Palette->GetPaletteColorsValue(3, nIndexSrcPalette);
    1379      197375 : }
    1380             : 
    1381           1 : void MMRRasterBand::AssignRGBColorDirectly(int nIndexDstCT, double dfValue)
    1382             : {
    1383           1 :     m_aadfPCT[0][nIndexDstCT] = dfValue;
    1384           1 :     m_aadfPCT[1][nIndexDstCT] = dfValue;
    1385           1 :     m_aadfPCT[2][nIndexDstCT] = dfValue;
    1386           1 :     m_aadfPCT[3][nIndexDstCT] = dfValue;
    1387           1 : }

Generated by: LCOV version 1.14