LCOV - code coverage report
Current view: top level - frmts/miramon - miramon_rel.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 99 115 86.1 %
Date: 2026-03-05 10:33:42 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  MiraMonRaster driver
       4             :  * Purpose:  Implements MMRRel: provides access to the REL file, which
       5             :  *           holds all the necessary metadata to correctly interpret and
       6             :  *           access the associated raw data.
       7             :  * Author:   Abel Pau
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2025, Xavier Pons
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #ifndef MMR_REL_H_INCLUDED
      16             : #define MMR_REL_H_INCLUDED
      17             : 
      18             : #include "cpl_string.h"
      19             : #include "gdal_priv.h"
      20             : #include "miramon_band.h"  // For MMRBand
      21             : 
      22             : #include "../miramon_common/mm_gdal_driver_structs.h"  // For SECTION_VERSIO
      23             : 
      24             : constexpr auto pszExtRaster = ".img";
      25             : constexpr auto pszExtRasterREL = "I.rel";
      26             : constexpr auto pszExtREL = ".rel";
      27             : constexpr auto LineReturn = "\r\n";
      28             : 
      29             : class MMRBand;
      30             : 
      31             : /************************************************************************/
      32             : /*                                MMRRel                                */
      33             : /************************************************************************/
      34             : 
      35             : enum class MMRNomFitxerState
      36             : {
      37             :     NOMFITXER_NOT_FOUND,        // There is no NomFitxer key
      38             :     NOMFITXER_VALUE_EXPECTED,   // The NomFitxer value is the expected
      39             :     NOMFITXER_VALUE_EMPTY,      // The NomFitxer value is empty
      40             :     NOMFITXER_VALUE_UNEXPECTED  // The NomFitxer value is unexpected
      41             : };
      42             : 
      43             : using ExcludedEntry = std::pair<CPLString, CPLString>;
      44             : 
      45             : class MMRRel
      46             : {
      47             :   public:
      48             :     MMRRel(const CPLString &, bool);  // Used in reading
      49             :     MMRRel(const CPLString &, bool bNeedOfNomFitxer, const CPLString &osEPSG,
      50             :            int nWidth, int nHeight, double dfMinX, double dfMaxX, double dfMinY,
      51             :            double dfMaxY,
      52             :            std::vector<MMRBand> &&oBands);  // Used in writing
      53             :     explicit MMRRel(const CPLString &);     // Used in writing. Simple version
      54             :     MMRRel(const MMRRel &) =
      55             :         delete;  // I don't want to construct a MMRDataset from another MMRDataset (effc++)
      56             :     MMRRel &operator=(const MMRRel &) =
      57             :         delete;  // I don't want to assign a MMRDataset to another MMRDataset (effc++)
      58             :     ~MMRRel();
      59             : 
      60             :     static CPLString
      61             :     GetValueFromSectionKeyPriorToREL(const CPLString &osPriorRelName,
      62             :                                      const CPLString &osSection,
      63             :                                      const CPLString &osKey);
      64             :     CPLString GetValueFromSectionKeyFromREL(const CPLString &osSection,
      65             :                                             const CPLString &osKey);
      66             :     static CPLString GetValueFromSectionKey(VSILFILE *pf,
      67             :                                             const CPLString &osSection,
      68             :                                             const CPLString &osKey);
      69             :     bool GetMetadataValue(const CPLString &osMainSection,
      70             :                           const CPLString &osSubSection,
      71             :                           const CPLString &osSubSubSection,
      72             :                           const CPLString &osKey, CPLString &osValue);
      73             :     bool GetMetadataValue(const CPLString &osMainSection,
      74             :                           const CPLString &osSubSection, const CPLString &osKey,
      75             :                           CPLString &osValue);
      76             :     bool GetMetadataValue(const CPLString &osSection, const CPLString &osKey,
      77             :                           CPLString &osValue);
      78             :     bool GetAndExcludeMetadataValueDirectly(const CPLString &osRELFile,
      79             :                                             const CPLString &osSection,
      80             :                                             const CPLString &osKey,
      81             :                                             CPLString &osValue);
      82             :     static bool GetMetadataValueDirectly(const CPLString &osRELFile,
      83             :                                          const CPLString &osSection,
      84             :                                          const CPLString &osKey,
      85             :                                          CPLString &osValue);
      86             :     void RELToGDALMetadata(GDALDataset *poDS);
      87             : 
      88             :     static CPLString MMRGetFileNameWithOutI(const CPLString &osRELFile);
      89             :     static CPLString MMRGetFileNameFromRelName(const CPLString &osRELFile,
      90             :                                                const CPLString &osExtension);
      91             :     int GetColumnsNumberFromREL();
      92             :     int GetRowsNumberFromREL();
      93             :     static int IdentifySubdataSetFile(const CPLString &osFileName);
      94             :     static int IdentifyFile(const GDALOpenInfo *poOpenInfo);
      95             :     CPLString GetColor_TractamentVariable(int nIBand) const;
      96             :     CPLString GetColor_Paleta(int nIBand) const;
      97             :     CPLErr UpdateGDALColorEntryFromBand(const CPLString &m_osBandSection,
      98             :                                         GDALColorEntry &m_sConstantColorRGB);
      99             : 
     100             :     void UpdateLineage(CSLConstList papszOptions, GDALDataset &oSrcDS);
     101             :     bool Write(GDALDataset &oSrcDS);
     102             :     void WriteMETADADES();
     103             :     void WriteIDENTIFICATION();
     104             :     void WriteOVERVIEW_ASPECTES_TECNICS(GDALDataset &oSrcDS);
     105             :     void WriteMetadataInComments(GDALDataset &oSrcDS);
     106             :     void WriteSPATIAL_REFERENCE_SYSTEM_HORIZONTAL();
     107             :     void WriteEXTENT();
     108             :     void WriteOVERVIEW();
     109             :     bool WriteATTRIBUTE_DATA(GDALDataset &oSrcDS);
     110             :     void WriteBandSection(const MMRBand &osBand, const CPLString &osDSDataType);
     111             :     void WriteCOLOR_TEXTSection();
     112             :     void WriteVISU_LLEGENDASection();
     113             :     void WriteLINEAGE(GDALDataset &oSrcDS);
     114             :     void WriteCurrentProcess();
     115             :     void WriteINOUTSection(const CPLString &osSection, int nInOut,
     116             :                            const CPLString &osIdentifierValue,
     117             :                            const CPLString &osSentitValue,
     118             :                            const CPLString &osTypeValuesValue,
     119             :                            const CPLString &osResultValueValue);
     120             :     void ImportAndWriteLineageSection(GDALDataset &oSrcDS);
     121             :     bool ProcessProcessSection(const CPLStringList &aosMiraMonSortedMetaData,
     122             :                                const CPLString &osProcessSection);
     123             :     void EndProcessesSection();
     124             : 
     125         492 :     bool IsValid() const
     126             :     {
     127         492 :         return m_bIsValid;
     128             :     }
     129             : 
     130           3 :     void SetIsValid(bool bIsValidIn)
     131             :     {
     132           3 :         m_bIsValid = bIsValidIn;
     133           3 :     }
     134             : 
     135       25858 :     VSILFILE *GetRELFile() const
     136             :     {
     137       25858 :         return m_pRELFile;
     138             :     }
     139             : 
     140         257 :     bool OpenRELFile(const char *pszAccess)
     141             :     {
     142         257 :         if (m_osRelFileName.empty())
     143           0 :             return false;
     144             : 
     145         257 :         m_pRELFile = VSIFOpenL(m_osRelFileName, pszAccess);
     146         257 :         if (m_pRELFile)
     147         257 :             return true;
     148           0 :         return false;
     149             :     }
     150             : 
     151         126 :     bool CreateRELFile()
     152             :     {
     153         126 :         if (m_osRelFileName.empty())
     154           0 :             return false;
     155             : 
     156         126 :         m_pRELFile = VSIFOpenL(m_osRelFileName, "wb");
     157         126 :         if (m_pRELFile)
     158         123 :             return true;
     159             : 
     160           3 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to create output file: %s",
     161             :                  m_osRelFileName.c_str());
     162             : 
     163           3 :         return false;
     164             :     }
     165             : 
     166         123 :     void AddRELVersion()
     167             :     {
     168         123 :         if (!m_pRELFile)
     169           0 :             return;
     170             : 
     171             :         // Writing MiraMon version section
     172         123 :         AddSectionStart(SECTION_VERSIO);
     173         123 :         AddKeyValue(KEY_VersMetaDades,
     174             :                     static_cast<unsigned>(MM_VERS_METADADES));
     175         123 :         AddKeyValue(KEY_SubVersMetaDades,
     176             :                     static_cast<unsigned>(MM_SUBVERS_METADADES));
     177         123 :         AddKeyValue(KEY_Vers, static_cast<unsigned>(MM_VERS));
     178         123 :         AddKeyValue(KEY_SubVers, static_cast<unsigned>(MM_SUBVERS));
     179         123 :         AddSectionEnd();
     180             :     }
     181             : 
     182         123 :     void AddCOLOR_TEXTVersion()
     183             :     {
     184         123 :         if (!m_pRELFile)
     185           0 :             return;
     186             : 
     187             :         // Writing COLOR_TEXT version keys
     188         123 :         AddKeyValue("Simb_Vers", 5);
     189         123 :         AddKeyValue("Simb_SubVers", 1);
     190             :     }
     191             : 
     192         123 :     void AddVISU_LLEGENDAVersion()
     193             :     {
     194         123 :         if (!m_pRELFile)
     195           0 :             return;
     196             : 
     197             :         // Writing VISU_LLEGENDA version keys
     198         123 :         AddKeyValue("LlegSimb_Vers", 4);
     199         123 :         AddKeyValue("LlegSimb_SubVers", 5);
     200             :     }
     201             : 
     202        1869 :     void AddSectionStart(const CPLString &osSection)
     203             :     {
     204        1869 :         if (!m_pRELFile)
     205           0 :             return;
     206             : 
     207        1869 :         VSIFPrintfL(m_pRELFile, "[%s]%s", osSection.c_str(), LineReturn);
     208             :     }
     209             : 
     210         246 :     void AddSectionStart(const CPLString &osSectionP1,
     211             :                          const CPLString &osSectionP2)
     212             :     {
     213         246 :         if (!m_pRELFile)
     214           0 :             return;
     215             : 
     216         246 :         VSIFPrintfL(m_pRELFile, "[%s:%s]%s", osSectionP1.c_str(),
     217             :                     osSectionP2.c_str(), LineReturn);
     218             :     }
     219             : 
     220        2151 :     void AddSectionEnd()
     221             :     {
     222        2151 :         if (!m_pRELFile)
     223           0 :             return;
     224             : 
     225        2151 :         VSIFPrintfL(m_pRELFile, LineReturn);
     226             :     }
     227             : 
     228         123 :     void AddKey(const CPLString &osKey)
     229             :     {
     230         123 :         if (!m_pRELFile)
     231           0 :             return;
     232             : 
     233         123 :         char *pzsKey = CPLRecode(osKey, CPL_ENC_UTF8, "CP1252");
     234         123 :         VSIFPrintfL(m_pRELFile, "%s=%s", pzsKey ? pzsKey : osKey.c_str(),
     235             :                     LineReturn);
     236         123 :         CPLFree(pzsKey);
     237             :     }
     238             : 
     239        4923 :     void AddKeyValue(const CPLString &osKey, const CPLString &osValue)
     240             :     {
     241        4923 :         if (!m_pRELFile)
     242           0 :             return;
     243             : 
     244        4923 :         char *pzsKey = CPLRecode(osKey, CPL_ENC_UTF8, "CP1252");
     245             : 
     246        9846 :         CPLString osValidValue = osValue;
     247        4923 :         size_t nPos = osValue.find(MMEmptyValue);
     248        4923 :         if (nPos != std::string::npos)
     249          34 :             osValidValue.replaceAll(MMEmptyValue, "");
     250             : 
     251        4923 :         if (osValidValue.empty())
     252             :         {
     253         523 :             VSIFPrintfL(m_pRELFile, "%s=%s", pzsKey ? pzsKey : osKey.c_str(),
     254             :                         LineReturn);
     255             :         }
     256             :         else
     257             :         {
     258        4400 :             char *pzsValue = CPLRecode(osValidValue, CPL_ENC_UTF8, "CP1252");
     259        4400 :             VSIFPrintfL(m_pRELFile, "%s=%s%s", pzsKey ? pzsKey : osKey.c_str(),
     260           0 :                         pzsValue ? pzsValue : osValidValue.c_str(), LineReturn);
     261        4400 :             CPLFree(pzsValue);
     262             :         }
     263        4923 :         CPLFree(pzsKey);
     264             :     }
     265             : 
     266        2706 :     void AddKeyValue(const CPLString &osKey, int nValue)
     267             :     {
     268        2706 :         if (!m_pRELFile)
     269           0 :             return;
     270             : 
     271        2706 :         char *pzsKey = CPLRecode(osKey, CPL_ENC_UTF8, "CP1252");
     272        2706 :         VSIFPrintfL(m_pRELFile, "%s=%d%s", pzsKey ? pzsKey : osKey.c_str(),
     273             :                     nValue, LineReturn);
     274             : 
     275        2706 :         CPLFree(pzsKey);
     276             :     }
     277             : 
     278         492 :     void AddKeyValue(const CPLString &osKey, unsigned nValue)
     279             :     {
     280         492 :         if (!m_pRELFile)
     281           0 :             return;
     282             : 
     283         492 :         char *pzsKey = CPLRecode(osKey, CPL_ENC_UTF8, "CP1252");
     284         492 :         VSIFPrintfL(m_pRELFile, "%s=%u%s", pzsKey ? pzsKey : osKey.c_str(),
     285             :                     nValue, LineReturn);
     286             : 
     287         492 :         CPLFree(pzsKey);
     288             :     }
     289             : 
     290         870 :     void AddKeyValue(const CPLString &osKey, double dfValue)
     291             :     {
     292         870 :         if (!m_pRELFile)
     293           0 :             return;
     294             : 
     295         870 :         char *pzsKey = CPLRecode(osKey, CPL_ENC_UTF8, "CP1252");
     296        1740 :         CPLString osValue = CPLSPrintf("%.15g", dfValue);
     297         870 :         VSIFPrintfL(m_pRELFile, "%s=%s%s", pzsKey ? pzsKey : osKey.c_str(),
     298             :                     osValue.c_str(), LineReturn);
     299             : 
     300         870 :         CPLFree(pzsKey);
     301             :     }
     302             : 
     303         698 :     void CloseRELFile()
     304             :     {
     305         698 :         if (!m_pRELFile)
     306         318 :             return;
     307             : 
     308         380 :         VSIFCloseL(m_pRELFile);
     309         380 :         m_pRELFile = nullptr;
     310             :     }
     311             : 
     312         289 :     const char *GetRELNameChar() const
     313             :     {
     314         289 :         return m_osRelFileName.c_str();
     315             :     }
     316             : 
     317         161 :     const CPLString &GetRELName() const
     318             :     {
     319         161 :         return m_osRelFileName;
     320             :     }
     321             : 
     322        3255 :     int GetNBands() const
     323             :     {
     324        3255 :         return m_nBands;
     325             :     }
     326             : 
     327        2770 :     MMRBand *GetBand(int nIBand)
     328             :     {
     329        2770 :         if (nIBand < 0 || nIBand >= m_nBands)
     330           0 :             return nullptr;
     331             : 
     332        2770 :         return &m_oBands[nIBand];
     333             :     }
     334             : 
     335             :     const CPLString &GetPattern() const
     336             :     {
     337             :         return osPattern;
     338             :     }
     339             : 
     340        8155 :     int isAMiraMonFile() const
     341             :     {
     342        8155 :         return m_bIsAMiraMonFile;
     343             :     }
     344             : 
     345       12624 :     void addExcludedSectionKey(const CPLString &section, const CPLString &key)
     346             :     {
     347       12624 :         m_ExcludedSectionKey.emplace(section, key);
     348       12624 :     }
     349             : 
     350       28916 :     std::set<ExcludedEntry> GetExcludedMetadata() const
     351             :     {
     352       28916 :         return m_ExcludedSectionKey;
     353             :     }
     354             : 
     355             :   private:
     356             :     static CPLErr CheckBandInRel(const CPLString &osRELFileName,
     357             :                                  const CPLString &osIMGFile);
     358             :     static CPLString MMRGetSimpleMetadataName(const CPLString &osLayerName);
     359             :     static bool SameFile(const CPLString &osFile1, const CPLString &osFile2);
     360             :     MMRNomFitxerState MMRStateOfNomFitxerInSection(const CPLString &osLayerName,
     361             :                                                    const CPLString &osSection,
     362             :                                                    const CPLString &osRELFile,
     363             :                                                    bool bNomFitxerMustExist);
     364             :     CPLString MMRGetAReferenceToIMGFile(const CPLString &osLayerName,
     365             :                                         const CPLString &osRELFile);
     366             : 
     367             :     CPLString GetAssociatedMetadataFileName(const CPLString &osFileName);
     368             : 
     369             :     void UpdateRELNameChar(const CPLString &osRelFileNameIn);
     370             :     CPLErr ParseBandInfo();
     371             : 
     372             :     CPLString m_osRelFileName = "";
     373             :     CPLString m_osTitle = "";
     374             :     VSILFILE *m_pRELFile = nullptr;
     375             :     static CPLString m_szImprobableRELChain;
     376             : 
     377             :     char m_szFileIdentifier[MM_MAX_LEN_LAYER_IDENTIFIER];
     378             : 
     379             :     bool m_bIsValid =
     380             :         false;  // Determines if the created object is valid or not.
     381             :     bool m_bIsAMiraMonFile = false;
     382             : 
     383             :     // List of rawBandNames in a subdataset
     384             :     std::vector<CPLString> m_papoSDSBands{};
     385             : 
     386             :     int m_nBands = 0;
     387             :     std::vector<MMRBand> m_oBands{};
     388             : 
     389             :     CPLString osPattern = "";  // A pattern used to create all band names
     390             : 
     391             :     // If there is only one band and the name of the rel is the same than the
     392             :     // name of the band (ex: band.img and bandI.rel) then NomFitxer
     393             :     // is not necessary to be written in the REL
     394             :     bool m_bNeedOfNomFitxer = true;
     395             : 
     396             :     // If a key-value pair is the same for all bands, it must be written
     397             :     // in a single general section. Otherwise, the most common key-value
     398             :     // (or any chosen one) can be written in the general section, and
     399             :     // all bands with a different value must write it in their
     400             :     // corresponding specific section.
     401             :     bool m_bDimAlreadyWritten = false;
     402             :     CPLString m_osDefTractVariable = "";
     403             :     CPLString m_osDefUnits = "";
     404             : 
     405             :     // Preserving metadata
     406             : 
     407             :     // List of excluded pairs {Section, Key} to be added to metadata
     408             :     // Empty Key means all section
     409             :     std::set<ExcludedEntry> m_ExcludedSectionKey = {};
     410             : 
     411             :     // For writing part
     412             :     // EPSG number
     413             :     CPLString m_osEPSG = "";
     414             : 
     415             :     // Global raster dimensions
     416             :     int m_nWidth = 0;
     417             :     int m_nHeight = 0;
     418             : 
     419             :     double m_dfMinX = MM_UNDEFINED_STATISTICAL_VALUE;
     420             :     double m_dfMaxX = -MM_UNDEFINED_STATISTICAL_VALUE;
     421             :     double m_dfMinY = MM_UNDEFINED_STATISTICAL_VALUE;
     422             :     double m_dfMaxY = -MM_UNDEFINED_STATISTICAL_VALUE;
     423             : 
     424             :     // Lineage
     425             :     CPLString m_osInFile = "";
     426             :     CPLString m_osOutFile = "";
     427             :     CPLStringList m_aosOptions{};
     428             : 
     429             :     // Number of processes in the lineage.
     430             :     // It is incremented each time a process is added
     431             :     // to the lineage, and it is used to set the "processes"
     432             :     // key in the QUALITY:LINEAGE section.
     433             :     int m_nNProcesses = 0;
     434             :     // It's possible to have a list of process like that:
     435             :     // processes=1,5,8 (nILastProcess=8)
     436             :     // So, current process would be 9 after the nILastProcess.
     437             :     int nILastProcess = 0;
     438             : 
     439             :     // List of processes
     440             :     CPLString m_osListOfProcesses = "";
     441             : };
     442             : 
     443             : #endif /* ndef MMR_REL_H_INCLUDED */

Generated by: LCOV version 1.14