LCOV - code coverage report
Current view: top level - frmts/wcs - wcsutils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 330 478 69.0 %
Date: 2026-02-12 23:49:34 Functions: 29 34 85.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  WCS Client Driver
       4             :  * Purpose:  Implementation of utilities.
       5             :  * Author:   Ari Jolma <ari dot jolma at gmail dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2006, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  * Copyright (c) 2017, Ari Jolma
      11             :  * Copyright (c) 2017, Finnish Environment Institute
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "ogr_spatialref.h"
      17             : #include "wcsutils.h"
      18             : #include <algorithm>
      19             : 
      20             : #define DIGITS "0123456789"
      21             : 
      22             : namespace WCSUtils
      23             : {
      24             : 
      25           0 : void Swap(double &a, double &b)
      26             : {
      27           0 :     double tmp = a;
      28           0 :     a = b;
      29           0 :     b = tmp;
      30           0 : }
      31             : 
      32          57 : std::string URLEncode(const std::string &str)
      33             : {
      34          57 :     char *pszEncoded = CPLEscapeString(str.c_str(), -1, CPLES_URL);
      35          57 :     std::string str2 = pszEncoded;
      36          57 :     CPLFree(pszEncoded);
      37          57 :     return str2;
      38             : }
      39             : 
      40         194 : std::string URLRemoveKey(const char *url, const std::string &key)
      41             : {
      42         388 :     CPLString retval = url;
      43         388 :     const std::string key_is = key + "=";
      44             :     while (true)
      45             :     {
      46         362 :         size_t pos = retval.ifind(key_is);
      47         362 :         if (pos != std::string::npos)
      48             :         {
      49         168 :             size_t end = retval.find("&", pos);
      50         168 :             retval.erase(pos, end - pos + 1);
      51             :         }
      52             :         else
      53             :         {
      54         194 :             break;
      55             :         }
      56         168 :     }
      57         194 :     if (!retval.empty() && retval.back() == '&')
      58             :     {
      59          96 :         retval.pop_back();
      60             :     }
      61         194 :     std::string retValAsStdString = std::move(retval);
      62         388 :     return retValAsStdString;
      63             : }
      64             : 
      65         117 : std::vector<std::string> &SwapFirstTwo(std::vector<std::string> &array)
      66             : {
      67         117 :     if (array.size() >= 2)
      68             :     {
      69         117 :         std::swap(array[0], array[1]);
      70             :     }
      71         117 :     return array;
      72             : }
      73             : 
      74        4015 : std::vector<std::string> Split(const char *value, const char *delim,
      75             :                                bool swap_the_first_two)
      76             : {
      77        8030 :     std::vector<std::string> array;
      78        4015 :     char **tokens = CSLTokenizeString2(
      79             :         value, delim,
      80             :         CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES | CSLT_HONOURSTRINGS);
      81        4015 :     int n = CSLCount(tokens);
      82       11874 :     for (int i = 0; i < n; ++i)
      83             :     {
      84        7859 :         array.push_back(tokens[i]);
      85             :     }
      86        4015 :     CSLDestroy(tokens);
      87        4015 :     if (swap_the_first_two && array.size() >= 2)
      88             :     {
      89         117 :         return SwapFirstTwo(array);
      90             :     }
      91        3898 :     return array;
      92             : }
      93             : 
      94         112 : std::string Join(const std::vector<std::string> &array, const char *delim,
      95             :                  bool swap_the_first_two)
      96             : {
      97         112 :     std::string str;
      98         112 :     const auto arraySize = array.size();
      99         345 :     for (unsigned int i = 0; i < arraySize; ++i)
     100             :     {
     101         233 :         if (i > 0)
     102             :         {
     103         121 :             str += delim;
     104             :         }
     105         233 :         if (swap_the_first_two)
     106             :         {
     107           0 :             if (i == 0 && arraySize >= 2)
     108             :             {
     109           0 :                 str += array[1];
     110             :             }
     111           0 :             else if (i == 1)
     112             :             {
     113           0 :                 str += array[0];
     114             :             }
     115             :         }
     116             :         else
     117             :         {
     118         233 :             str += array[i];
     119             :         }
     120             :     }
     121         112 :     return str;
     122             : }
     123             : 
     124          51 : std::vector<int> Ilist(const std::vector<std::string> &array, unsigned int from,
     125             :                        size_t count)
     126             : {
     127          51 :     std::vector<int> retval;
     128         156 :     for (unsigned int i = from; i < array.size() && i < from + count; ++i)
     129             :     {
     130         105 :         retval.push_back(atoi(array[i].c_str()));
     131             :     }
     132          51 :     return retval;
     133             : }
     134             : 
     135         294 : std::vector<double> Flist(const std::vector<std::string> &array,
     136             :                           unsigned int from, size_t count)
     137             : {
     138         294 :     std::vector<double> retval;
     139         762 :     for (unsigned int i = from; i < array.size() && i < from + count; ++i)
     140             :     {
     141         468 :         retval.push_back(CPLAtof(array[i].c_str()));
     142             :     }
     143         294 :     return retval;
     144             : }
     145             : 
     146          85 : int IndexOf(const std::string &str, const std::vector<std::string> &array)
     147             : {
     148          85 :     int index = -1;
     149         141 :     for (unsigned int i = 0; i < array.size(); ++i)
     150             :     {
     151         135 :         if (array[i] == str)
     152             :         {
     153          79 :             index = i;
     154          79 :             break;
     155             :         }
     156             :     }
     157          85 :     return index;
     158             : }
     159             : 
     160           0 : int IndexOf(int i, const std::vector<int> &array)
     161             : {
     162           0 :     int index = -1;
     163           0 :     for (unsigned int j = 0; j < array.size(); ++j)
     164             :     {
     165           0 :         if (array[j] == i)
     166             :         {
     167           0 :             index = j;
     168           0 :             break;
     169             :         }
     170             :     }
     171           0 :     return index;
     172             : }
     173             : 
     174          21 : std::vector<int> IndexOf(const std::vector<std::string> &strs,
     175             :                          const std::vector<std::string> &array)
     176             : {
     177          21 :     std::vector<int> retval;
     178          49 :     for (unsigned int i = 0; i < strs.size(); ++i)
     179             :     {
     180          28 :         retval.push_back(IndexOf(strs[i], array));
     181             :     }
     182          21 :     return retval;
     183             : }
     184             : 
     185         210 : int IndexOf(const std::string &key,
     186             :             const std::vector<std::vector<std::string>> &kvps)
     187             : {
     188         210 :     int index = -1;
     189         420 :     for (unsigned int i = 0; i < kvps.size(); ++i)
     190             :     {
     191         210 :         if (kvps[i].size() > 1 && key == kvps[i][0])
     192             :         {
     193           0 :             index = i;
     194           0 :             break;
     195             :         }
     196             :     }
     197         210 :     return index;
     198             : }
     199             : 
     200          21 : bool Contains(const std::vector<int> &array, int value)
     201             : {
     202          49 :     for (unsigned int i = 0; i < array.size(); ++i)
     203             :     {
     204          28 :         if (array[i] == value)
     205             :         {
     206           0 :             return true;
     207             :         }
     208             :     }
     209          21 :     return false;
     210             : }
     211             : 
     212           6 : std::string FromParenthesis(const std::string &s)
     213             : {
     214           6 :     size_t beg = s.find_first_of("(");
     215           6 :     size_t end = s.find_last_of(")");
     216           6 :     if (beg == std::string::npos || end == std::string::npos)
     217             :     {
     218           0 :         return "";
     219             :     }
     220           6 :     return s.substr(beg + 1, end - beg - 1);
     221             : }
     222             : 
     223             : std::vector<std::string>
     224           0 : ParseSubset(const std::vector<std::string> &subset_array,
     225             :             const std::string &dim)
     226             : {
     227             :     // array is SUBSET defs, a SUBSET def is dim[,crs](low[,high])
     228           0 :     std::vector<std::string> retval;
     229             :     unsigned int i;
     230           0 :     std::string params;
     231           0 :     for (i = 0; i < subset_array.size(); ++i)
     232             :     {
     233           0 :         params = subset_array[i];
     234           0 :         size_t pos = params.find(dim + "(");
     235           0 :         if (pos != std::string::npos)
     236             :         {
     237           0 :             retval.push_back("");  // crs
     238           0 :             break;
     239             :         }
     240           0 :         pos = params.find(dim + ",");
     241           0 :         if (pos != std::string::npos)
     242             :         {
     243           0 :             params.erase(0, pos + 1);
     244           0 :             pos = params.find("(");
     245           0 :             retval.push_back(params.substr(0, pos - 1));
     246           0 :             break;
     247             :         }
     248             :     }
     249           0 :     if (retval.size() > 0)
     250             :     {
     251             :         std::vector<std::string> params_array =
     252           0 :             Split(FromParenthesis(params).c_str(), ",");
     253           0 :         retval.push_back(params_array[0]);
     254           0 :         if (params_array.size() > 1)
     255             :         {
     256           0 :             retval.push_back(params_array[1]);
     257             :         }
     258             :         else
     259             :         {
     260           0 :             retval.push_back("");
     261             :         }
     262             :     }
     263           0 :     return retval;
     264             : }
     265             : 
     266             : /* -------------------------------------------------------------------- */
     267             : /*      FileIsReadable                                                  */
     268             : /* -------------------------------------------------------------------- */
     269             : 
     270         145 : bool FileIsReadable(const std::string &filename)
     271             : {
     272         145 :     VSILFILE *file = VSIFOpenL(filename.c_str(), "r");
     273         145 :     if (file)
     274             :     {
     275         120 :         VSIFCloseL(file);
     276         120 :         return true;
     277             :     }
     278          25 :     return false;
     279             : }
     280             : 
     281          96 : std::string RemoveExt(const std::string &filename)
     282             : {
     283          96 :     size_t pos = filename.find_last_of(".");
     284          96 :     if (pos != std::string::npos)
     285             :     {
     286          96 :         return filename.substr(0, pos);
     287             :     }
     288           0 :     return filename;
     289             : }
     290             : 
     291             : /* -------------------------------------------------------------------- */
     292             : /*      MakeDir                                                         */
     293             : /* -------------------------------------------------------------------- */
     294             : 
     295         122 : bool MakeDir(const std::string &dirname)
     296             : {
     297             :     VSIStatBufL stat;
     298         122 :     if (VSIStatL(dirname.c_str(), &stat) != 0)
     299             :     {
     300          50 :         std::string parent = CPLGetDirnameSafe(dirname.c_str());
     301          25 :         if (!parent.empty() && parent != ".")
     302             :         {
     303          25 :             if (!MakeDir(parent))
     304             :             {
     305           0 :                 return false;
     306             :             }
     307             :         }
     308          25 :         return VSIMkdir(dirname.c_str(), 0755) == 0;
     309             :     }
     310          97 :     return true;
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                        SearchChildWithValue()                        */
     315             : /************************************************************************/
     316             : 
     317          72 : CPLXMLNode *SearchChildWithValue(CPLXMLNode *node, const char *path,
     318             :                                  const char *value)
     319             : {
     320          72 :     if (node == nullptr)
     321             :     {
     322           0 :         return nullptr;
     323             :     }
     324         427 :     for (CPLXMLNode *child = node->psChild; child != nullptr;
     325         355 :          child = child->psNext)
     326             :     {
     327         427 :         if (EQUAL(CPLGetXMLValue(child, path, ""), value))
     328             :         {
     329          72 :             return child;
     330             :         }
     331             :     }
     332           0 :     return nullptr;
     333             : }
     334             : 
     335         256 : bool CPLGetXMLBoolean(CPLXMLNode *poRoot, const char *pszPath)
     336             : {
     337             :     // returns true if path exists and does not contain untrue value
     338         256 :     poRoot = CPLGetXMLNode(poRoot, pszPath);
     339         256 :     if (poRoot == nullptr)
     340             :     {
     341         189 :         return false;
     342             :     }
     343          67 :     return CPLTestBool(CPLGetXMLValue(poRoot, nullptr, ""));
     344             : }
     345             : 
     346         261 : bool CPLUpdateXML(CPLXMLNode *poRoot, const char *pszPath,
     347             :                   const char *new_value)
     348             : {
     349         522 :     std::string old_value = CPLGetXMLValue(poRoot, pszPath, "");
     350         261 :     if (new_value != old_value)
     351             :     {
     352         160 :         CPLSetXMLValue(poRoot, pszPath, new_value);
     353         160 :         return true;
     354             :     }
     355         101 :     return false;
     356             : }
     357             : 
     358             : /* -------------------------------------------------------------------- */
     359             : /*      XMLCopyMetadata                                                 */
     360             : /*      Copy child node 'key' into metadata as MDI element.             */
     361             : /* -------------------------------------------------------------------- */
     362             : 
     363          67 : void XMLCopyMetadata(CPLXMLNode *parent, CPLXMLNode *metadata,
     364             :                      const std::string &key)
     365             : {
     366          67 :     CPLXMLNode *node = CPLGetXMLNode(parent, key.c_str());
     367          67 :     if (node)
     368             :     {
     369          40 :         CPLAddXMLAttributeAndValue(
     370             :             CPLCreateXMLElementAndValue(metadata, "MDI",
     371             :                                         CPLGetXMLValue(node, nullptr, "")),
     372             :             "key", key.c_str());
     373             :     }
     374          67 : }
     375             : 
     376             : /* -------------------------------------------------------------------- */
     377             : /*      SetupCache                                                      */
     378             : /*      Cache is a directory                                            */
     379             : /*      The file db is the cache index with lines of unique_key=URL     */
     380             : /* -------------------------------------------------------------------- */
     381             : 
     382          97 : bool SetupCache(std::string &cache, bool clear)
     383             : {
     384          97 :     if (cache == "")
     385             :     {
     386             : #ifdef _WIN32
     387             :         const char *home = CPLGetConfigOption("USERPROFILE", nullptr);
     388             : #else
     389           1 :         const char *home = CPLGetConfigOption("HOME", nullptr);
     390             : #endif
     391           1 :         if (home)
     392             :         {
     393           1 :             cache = CPLFormFilenameSafe(home, ".gdal", nullptr);
     394             :         }
     395             :         else
     396             :         {
     397           0 :             const char *dir = CPLGetConfigOption("CPL_TMPDIR", nullptr);
     398           0 :             if (!dir)
     399           0 :                 dir = CPLGetConfigOption("TMPDIR", nullptr);
     400           0 :             if (!dir)
     401           0 :                 dir = CPLGetConfigOption("TEMP", nullptr);
     402           0 :             const char *username = CPLGetConfigOption("USERNAME", nullptr);
     403           0 :             if (!username)
     404           0 :                 username = CPLGetConfigOption("USER", nullptr);
     405           0 :             if (dir && username)
     406             :             {
     407           0 :                 std::string subdir = ".gdal_";
     408           0 :                 subdir += username;
     409           0 :                 cache = CPLFormFilenameSafe(dir, subdir.c_str(), nullptr);
     410             :             }
     411             :         }
     412           1 :         cache = CPLFormFilenameSafe(cache.c_str(), "wcs_cache", nullptr);
     413             :     }
     414          97 :     if (!MakeDir(cache))
     415             :     {
     416           0 :         return false;
     417             :     }
     418          97 :     if (clear)
     419             :     {
     420           0 :         char **folder = VSIReadDir(cache.c_str());
     421           0 :         int size = folder ? CSLCount(folder) : 0;
     422           0 :         for (int i = 0; i < size; i++)
     423             :         {
     424           0 :             if (folder[i][0] == '.')
     425             :             {
     426           0 :                 continue;
     427             :             }
     428             :             const std::string filepath =
     429           0 :                 CPLFormFilenameSafe(cache.c_str(), folder[i], nullptr);
     430           0 :             CPL_IGNORE_RET_VAL(VSIUnlink(filepath.c_str()));
     431             :         }
     432           0 :         CSLDestroy(folder);
     433             :     }
     434             :     // make sure the index exists and is writable
     435         194 :     const std::string db = CPLFormFilenameSafe(cache.c_str(), "db", nullptr);
     436          97 :     VSILFILE *f = VSIFOpenL(db.c_str(), "r");
     437          97 :     if (f)
     438             :     {
     439          72 :         VSIFCloseL(f);
     440             :     }
     441             :     else
     442             :     {
     443          25 :         f = VSIFOpenL(db.c_str(), "w");
     444          25 :         if (f)
     445             :         {
     446          25 :             VSIFCloseL(f);
     447             :         }
     448             :         else
     449             :         {
     450           0 :             CPLError(CE_Failure, CPLE_FileIO, "Can't open file '%s': %i\n",
     451           0 :                      db.c_str(), errno);
     452           0 :             return false;
     453             :         }
     454             :     }
     455          97 :     srand((unsigned int)time(
     456             :         nullptr));  // not to have the same names in the cache
     457          97 :     return true;
     458             : }
     459             : 
     460           0 : std::vector<std::string> ReadCache(const std::string &cache)
     461             : {
     462           0 :     std::vector<std::string> contents;
     463           0 :     const std::string db = CPLFormFilenameSafe(cache.c_str(), "db", nullptr);
     464           0 :     char **data = CSLLoad(db.c_str());
     465           0 :     if (data)
     466             :     {
     467           0 :         for (int i = 0; data[i]; ++i)
     468             :         {
     469           0 :             char *val = strchr(data[i], '=');
     470           0 :             if (val != nullptr && *val == '=')
     471             :             {
     472           0 :                 val += 1;
     473           0 :                 if (strcmp(val, "bar") != 0)
     474             :                 {
     475           0 :                     contents.push_back(val);
     476             :                 }
     477             :             }
     478             :         }
     479           0 :         CSLDestroy(data);
     480             :     }
     481           0 :     if (!contents.empty())
     482           0 :         std::sort(contents.begin(), contents.end());
     483           0 :     return contents;
     484             : }
     485             : 
     486             : /* -------------------------------------------------------------------- */
     487             : /*      DeleteEntryFromCache                                            */
     488             : /*      Examines the 'db' file in the cache, which contains             */
     489             : /*      unique key=value pairs, one per line. This function             */
     490             : /*      deletes pairs based on the given key and/or value.              */
     491             : /*      If key or value is empty it is not considered.                  */
     492             : /*      The key is taken as a basename of a file in the cache           */
     493             : /*      and all files with the basename is deleted.                     */
     494             : /* -------------------------------------------------------------------- */
     495             : 
     496           0 : bool DeleteEntryFromCache(const std::string &cache, const std::string &key,
     497             :                           const std::string &value)
     498             : {
     499             :     // Depending on which one of key and value is not "" delete the relevant
     500             :     // entry.
     501           0 :     const std::string db = CPLFormFilenameSafe(cache.c_str(), "db", nullptr);
     502             :     char **data =
     503           0 :         CSLLoad(db.c_str());  // returns NULL in error and for empty files
     504           0 :     char **data2 = CSLAddNameValue(nullptr, "foo", "bar");
     505           0 :     std::string filename = "";
     506           0 :     if (data)
     507             :     {
     508           0 :         for (int i = 0; data[i]; ++i)
     509             :         {
     510           0 :             char *val = strchr(data[i], '=');
     511           0 :             if (val != nullptr && *val == '=')
     512             :             {
     513           0 :                 *val = '\0';
     514           0 :                 val = val + 1;
     515           0 :                 if ((key != "" && key == data[i]) ||
     516           0 :                     (value != "" && value == val) ||
     517           0 :                     (strcmp(data[i], "foo") == 0))
     518             :                 {
     519           0 :                     if (key != "")
     520             :                     {
     521           0 :                         filename = data[i];
     522             :                     }
     523           0 :                     else if (value != "")
     524             :                     {
     525           0 :                         filename = data[i];
     526             :                     }
     527           0 :                     continue;
     528             :                 }
     529           0 :                 data2 = CSLAddNameValue(data2, data[i], val);
     530             :             }
     531             :         }
     532           0 :         CSLDestroy(data);
     533             :     }
     534           0 :     CSLSave(data2, db.c_str());  // returns 0 in error and for empty arrays
     535           0 :     CSLDestroy(data2);
     536           0 :     if (filename != "")
     537             :     {
     538           0 :         char **folder = VSIReadDir(cache.c_str());
     539           0 :         int size = folder ? CSLCount(folder) : 0;
     540           0 :         for (int i = 0; i < size; i++)
     541             :         {
     542           0 :             if (folder[i][0] == '.')
     543             :             {
     544           0 :                 continue;
     545             :             }
     546           0 :             std::string name = folder[i];
     547           0 :             if (name.find(filename) != std::string::npos)
     548             :             {
     549             :                 const std::string filepath =
     550           0 :                     CPLFormFilenameSafe(cache.c_str(), name.c_str(), nullptr);
     551           0 :                 if (VSIUnlink(filepath.c_str()) == -1)
     552             :                 {
     553             :                     // error but can't do much, raise a warning?
     554             :                 }
     555             :             }
     556             :         }
     557           0 :         CSLDestroy(folder);
     558             :     }
     559           0 :     return true;
     560             : }
     561             : 
     562             : /* -------------------------------------------------------------------- */
     563             : /*      SearchCache                                                     */
     564             : /*      The key,value pairs in the cache index file 'db' is searched    */
     565             : /*      for the first pair where the value is the given url. If one     */
     566             : /*      is found, the filename is formed from the cache directory name, */
     567             : /*      the key, and the ext.                                           */
     568             : /* -------------------------------------------------------------------- */
     569             : 
     570         144 : CPLErr SearchCache(const std::string &cache, const std::string &url,
     571             :                    std::string &filename, const std::string &ext, bool &found)
     572             : {
     573         144 :     found = false;
     574         288 :     const std::string db = CPLFormFilenameSafe(cache.c_str(), "db", nullptr);
     575         144 :     VSILFILE *f = VSIFOpenL(db.c_str(), "r");
     576         144 :     if (!f)
     577             :     {
     578           0 :         CPLError(CE_Failure, CPLE_FileIO, "Can't open file '%s': %i\n",
     579           0 :                  db.c_str(), errno);
     580           0 :         return CE_Failure;
     581             :     }
     582         216 :     while (const char *line = CPLReadLineL(f))
     583             :     {
     584         144 :         char *value = strchr((char *)line, '=');
     585         144 :         if (value == nullptr || *value != '=')
     586             :         {
     587           0 :             continue;
     588             :         }
     589         144 :         *value = '\0';
     590         144 :         if (url == (value + 1))
     591             :         {
     592          72 :             filename = line;
     593          72 :             found = true;
     594          72 :             break;
     595             :         }
     596          72 :     }
     597         144 :     VSIFCloseL(f);
     598         144 :     if (found)
     599             :     {
     600         144 :         filename = CPLFormFilenameSafe(cache.c_str(), (filename + ext).c_str(),
     601          72 :                                        nullptr);
     602          72 :         found = FileIsReadable(filename);
     603             :         // if not readable, we should delete the entry
     604             :     }
     605         144 :     return CE_None;
     606             : }
     607             : 
     608             : /* -------------------------------------------------------------------- */
     609             : /*      AddEntryToCache                                                 */
     610             : /*      A new unique key is created into the database based on the      */
     611             : /*      filename replacing X with a random ascii character.             */
     612             : /*      The returned filename is a path formed from the cache directory */
     613             : /*      name, the filename, and the ext.                                */
     614             : /* -------------------------------------------------------------------- */
     615             : 
     616          48 : CPLErr AddEntryToCache(const std::string &cache, const std::string &url,
     617             :                        std::string &filename, const std::string &ext)
     618             : {
     619             :     // todo: check for lock and do something if locked(?)
     620             :     // todo: lock the cache
     621             :     // assuming the url is not in the cache
     622          96 :     const std::string store = filename;
     623          96 :     const std::string db = CPLFormFilenameSafe(cache.c_str(), "db", nullptr);
     624          48 :     VSILFILE *f = VSIFOpenL(db.c_str(), "a");
     625          48 :     if (!f)
     626             :     {
     627           0 :         CPLError(CE_Failure, CPLE_FileIO, "Can't open file '%s': %i\n",
     628           0 :                  db.c_str(), errno);
     629           0 :         return CE_Failure;
     630             :     }
     631             : 
     632             :     // create a new file into the cache using filename as template
     633         144 :     std::string path = "";
     634             :     VSIStatBufL stat;
     635          24 :     do
     636             :     {
     637          72 :         filename = store;
     638             :         static const char chars[] =
     639             :             "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
     640         432 :         for (size_t i = 0; i < filename.length(); ++i)
     641             :         {
     642         360 :             if (filename.at(i) == 'X')
     643             :             {
     644             : #ifndef __COVERITY__
     645         360 :                 filename.replace(i, 1, 1, chars[rand() % (sizeof(chars) - 1)]);
     646             : #else
     647             :                 filename.replace(i, 1, 1, chars[i % (sizeof(chars) - 1)]);
     648             : #endif
     649             :             }
     650             :         }
     651             :         // replace X with random character from a-zA-Z
     652         144 :         path = CPLFormFilenameSafe(cache.c_str(), (filename + ext).c_str(),
     653          72 :                                    nullptr);
     654          72 :     } while (VSIStatExL(path.c_str(), &stat, VSI_STAT_EXISTS_FLAG) == 0);
     655          48 :     VSILFILE *f2 = VSIFOpenL(path.c_str(), "w");
     656          48 :     if (f2)
     657             :     {
     658          48 :         VSIFCloseL(f2);
     659             :     }
     660             : 
     661             :     std::string entry =
     662          96 :         filename + "=" + url + "\n";  // '=' for compatibility with CSL
     663          48 :     VSIFWriteL(entry.c_str(), sizeof(char), entry.size(), f);
     664          48 :     VSIFCloseL(f);
     665             : 
     666          48 :     filename = std::move(path);
     667          48 :     return CE_None;
     668             : }
     669             : 
     670             : // steps into element 'from' and adds values of elements 'keys' into the
     671             : // metadata 'path' is the key that is used for metadata and it is appended with
     672             : // 'from' path may be later used to get metadata from elements below 'from' so
     673             : // it is returned in the appended form
     674         134 : CPLXMLNode *AddSimpleMetaData(char ***metadata, CPLXMLNode *node,
     675             :                               std::string &path, const std::string &from,
     676             :                               const std::vector<std::string> &keys)
     677             : {
     678         134 :     CPLXMLNode *node2 = CPLGetXMLNode(node, from.c_str());
     679         134 :     if (node2)
     680             :     {
     681         134 :         path = path + from + ".";
     682         556 :         for (unsigned int i = 0; i < keys.size(); i++)
     683             :         {
     684         422 :             CPLXMLNode *node3 = CPLGetXMLNode(node2, keys[i].c_str());
     685         422 :             if (node3)
     686             :             {
     687         512 :                 const std::string name = path + keys[i];
     688         256 :                 CPLString value = CPLGetXMLValue(node3, nullptr, "");
     689         256 :                 value.Trim();
     690         256 :                 *metadata =
     691         256 :                     CSLSetNameValue(*metadata, name.c_str(), value.c_str());
     692             :             }
     693             :         }
     694             :     }
     695         134 :     return node2;
     696             : }
     697             : 
     698         211 : std::string GetKeywords(CPLXMLNode *root, const std::string &path,
     699             :                         const std::string &kw)
     700             : {
     701         211 :     std::string words = "";
     702             :     CPLXMLNode *keywords =
     703         211 :         (path != "") ? CPLGetXMLNode(root, path.c_str()) : root;
     704         211 :     if (keywords)
     705             :     {
     706         262 :         std::vector<unsigned int> epsg_codes;
     707       36077 :         for (CPLXMLNode *node = keywords->psChild; node != nullptr;
     708       35946 :              node = node->psNext)
     709             :         {
     710       35946 :             if (node->eType != CXT_Element)
     711             :             {
     712           6 :                 continue;
     713             :             }
     714       35940 :             if (kw == node->pszValue)
     715             :             {
     716       35886 :                 CPLString word = CPLGetXMLValue(node, nullptr, "");
     717       17943 :                 word.Trim();
     718             : 
     719             :                 // crs, replace "http://www.opengis.net/def/crs/EPSG/0/"
     720             :                 // or "urn:ogc:def:crs:EPSG::" with EPSG:
     721       17943 :                 const char *const epsg[] = {
     722             :                     "http://www.opengis.net/def/crs/EPSG/0/",
     723             :                     "urn:ogc:def:crs:EPSG::"};
     724       53829 :                 for (unsigned int i = 0; i < CPL_ARRAYSIZE(epsg); i++)
     725             :                 {
     726       35886 :                     size_t pos = word.find(epsg[i]);
     727       35886 :                     if (pos == 0)
     728             :                     {
     729             :                         std::string code =
     730       17564 :                             word.substr(strlen(epsg[i]), std::string::npos);
     731       17564 :                         if (code.find_first_not_of(DIGITS) == std::string::npos)
     732             :                         {
     733       17564 :                             epsg_codes.push_back(atoi(code.c_str()));
     734       17564 :                             continue;
     735             :                         }
     736             :                     }
     737             :                 }
     738             : 
     739             :                 // profiles, remove http://www.opengis.net/spec/
     740             :                 // interpolation, remove
     741             :                 // http://www.opengis.net/def/interpolation/OGC/1/
     742             : 
     743       17943 :                 const char *const spec[] = {
     744             :                     "http://www.opengis.net/spec/",
     745             :                     "http://www.opengis.net/def/interpolation/OGC/1/"};
     746       53829 :                 for (unsigned int i = 0; i < CPL_ARRAYSIZE(spec); i++)
     747             :                 {
     748       35886 :                     size_t pos = word.find(spec[i]);
     749       35886 :                     if (pos != std::string::npos)
     750             :                     {
     751         118 :                         word.erase(pos, strlen(spec[i]));
     752             :                     }
     753             :                 }
     754             : 
     755       17943 :                 if (words != "")
     756             :                 {
     757       17881 :                     words += ",";
     758             :                 }
     759       17943 :                 words += word;
     760             :             }
     761             :         }
     762         131 :         if (epsg_codes.size() > 0)
     763             :         {
     764           8 :             std::string codes;
     765           8 :             std::sort(epsg_codes.begin(), epsg_codes.end());
     766           8 :             unsigned int pajazzo = 0, i = 0, a = 0, b = 0;
     767             :             while (1)
     768             :             {
     769             :                 // cppcheck-suppress containerOutOfBounds
     770       17572 :                 unsigned int c = i < epsg_codes.size() ? epsg_codes[i] : 0;
     771       17572 :                 if (pajazzo == 1)
     772             :                 {
     773        1967 :                     if (c > a + 1)
     774             :                     {
     775        1194 :                         if (codes != "")
     776             :                         {
     777        1189 :                             codes += ",";
     778             :                         }
     779        1194 :                         codes += CPLString().Printf("%i", a);
     780        1194 :                         a = c;
     781             :                     }
     782         773 :                     else if (c >= a)
     783             :                     {
     784         765 :                         b = c;
     785         765 :                         pajazzo = 2;
     786             :                     }
     787             :                 }
     788       15605 :                 else if (pajazzo == 2)
     789             :                 {
     790       15597 :                     if (c > b + 1)
     791             :                     {
     792         765 :                         if (codes != "")
     793             :                         {
     794         762 :                             codes += ",";
     795             :                         }
     796         765 :                         codes += CPLString().Printf("%i:%i", a, b);
     797         765 :                         a = c;
     798         765 :                         pajazzo = 1;
     799             :                     }
     800       14832 :                     else if (c >= b)
     801             :                     {
     802       14832 :                         b = c;
     803             :                     }
     804             :                 }
     805             :                 else
     806             :                 {  // pajazzo == 0
     807           8 :                     a = c;
     808           8 :                     pajazzo = 1;
     809             :                 }
     810       17572 :                 if (i == epsg_codes.size())
     811             :                 {
     812             :                     // must empty the pajazzo before leaving
     813           8 :                     if (codes != "")
     814             :                     {
     815           8 :                         codes += ",";
     816             :                     }
     817           8 :                     if (pajazzo == 1)
     818             :                     {
     819           8 :                         codes += CPLString().Printf("%i", a);
     820             :                     }
     821           0 :                     else if (pajazzo == 2)
     822             :                     {
     823           0 :                         codes += CPLString().Printf("%i:%i", a, b);
     824             :                     }
     825           8 :                     break;
     826             :                 }
     827       17564 :                 ++i;
     828       17564 :             }
     829           8 :             if (words != "")
     830             :             {
     831           8 :                 words += ",";
     832             :             }
     833           8 :             words += "EPSG:" + codes;
     834             :         }
     835             :     }
     836         211 :     return words;
     837             : }
     838             : 
     839         147 : std::string ParseCRS(CPLXMLNode *node)
     840             : {
     841             :     // test for attrs crs (OWS) and srsName (GML), and text contents of subnode
     842             :     // (GridBaseCRS)
     843         147 :     std::string crs = CPLGetXMLValue(node, "crs", "");
     844         147 :     if (crs == "")
     845             :     {
     846          57 :         crs = CPLGetXMLValue(node, "srsName", "");
     847          57 :         if (crs == "")
     848             :         {
     849          36 :             crs = CPLGetXMLValue(node, "GridBaseCRS", "");
     850             :         }
     851             :     }
     852         147 :     if (crs == "")
     853             :     {
     854           0 :         return crs;
     855             :     }
     856             :     // split compound names
     857             :     // see for example
     858             :     // http://www.eurogeographics.org/sites/default/files/2016-01-18_INSPIRE-KEN-CovFaq.pdf
     859         147 :     size_t pos = crs.find("?");
     860         147 :     if (pos != std::string::npos)
     861             :     {
     862           3 :         if (crs.find("crs-compound?") != std::string::npos)
     863             :         {  // 1=uri&2=uri...
     864             :             // assuming the first is for X,Y
     865           3 :             crs = crs.substr(pos + 1);
     866           3 :             pos = crs.find("&");
     867           3 :             if (pos != std::string::npos)
     868             :             {
     869           3 :                 pos = pos - 2;
     870             :             }
     871           3 :             crs = crs.substr(2, pos);
     872             :         }
     873             :     }
     874         147 :     return crs;
     875             : }
     876             : 
     877             : // if appropriate, try to create WKT description from CRS name
     878             : // return false if failure
     879             : // appropriate means, that the name is a real CRS
     880          57 : bool CRS2Projection(const std::string &crs, OGRSpatialReference *sr,
     881             :                     char **projection)
     882             : {
     883          57 :     if (*projection != nullptr)
     884             :     {
     885           0 :         CPLFree(*projection);
     886             :     }
     887          57 :     *projection = nullptr;
     888          57 :     if (crs.empty())
     889             :     {
     890           0 :         return true;
     891             :     }
     892         114 :     if (crs.find(":imageCRS") != std::string::npos ||
     893         114 :         crs.find("/Index1D") != std::string::npos ||
     894         114 :         crs.find("/Index2D") != std::string::npos ||
     895         171 :         crs.find("/Index3D") != std::string::npos ||
     896          57 :         crs.find("/AnsiDate") != std::string::npos)
     897             :     {
     898             :         // not a map projection
     899           0 :         return true;
     900             :     }
     901         114 :     std::string crs2 = crs;
     902             :     // rasdaman uses urls, which return gml:ProjectedCRS XML, which is not
     903             :     // recognized by GDAL currently
     904          57 :     if (crs2.find("EPSG") != std::string::npos)
     905             :     {  // ...EPSG...(\d+)
     906          57 :         size_t pos1 = crs2.find_last_of(DIGITS);
     907          57 :         if (pos1 != std::string::npos)
     908             :         {
     909          57 :             size_t pos2 = pos1 - 1;
     910          57 :             char c = crs2.at(pos2);
     911         231 :             while (strchr(DIGITS, c))
     912             :             {
     913         174 :                 pos2 = pos2 - 1;
     914         174 :                 c = crs2.at(pos2);
     915             :             }
     916          57 :             crs2 = "EPSGA:" + crs2.substr(pos2 + 1, pos1 - pos2);
     917             :         }
     918             :     }
     919         114 :     OGRSpatialReference local_sr;
     920          57 :     OGRSpatialReference *sr_pointer = sr != nullptr ? sr : &local_sr;
     921          57 :     if (sr_pointer->SetFromUserInput(
     922             :             crs2.c_str(),
     923          57 :             OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) ==
     924             :         OGRERR_NONE)
     925             :     {
     926          57 :         sr_pointer->exportToWkt(projection);
     927          57 :         return true;
     928             :     }
     929           0 :     return false;
     930             : }
     931             : 
     932          57 : bool CRSImpliesAxisOrderSwap(const std::string &crs, bool &swap,
     933             :                              char **projection)
     934             : {
     935         114 :     OGRSpatialReference oSRS;
     936          57 :     char *tmp = nullptr;
     937          57 :     swap = false;
     938          57 :     if (!CRS2Projection(crs, &oSRS, &tmp))
     939             :     {
     940           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     941             :                  "Unable to interpret coverage CRS '%s'.", crs.c_str());
     942           0 :         CPLFree(tmp);
     943           0 :         return false;
     944             :     }
     945          57 :     if (tmp)
     946             :     {
     947          57 :         if (projection != nullptr)
     948             :         {
     949          57 :             *projection = tmp;
     950             :         }
     951             :         else
     952             :         {
     953           0 :             CPLFree(tmp);
     954             :         }
     955          57 :         swap = oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting();
     956             :     }
     957          57 :     return true;
     958             : }
     959             : 
     960          21 : std::vector<std::vector<int>> ParseGridEnvelope(CPLXMLNode *node,
     961             :                                                 bool swap_the_first_two)
     962             : {
     963          21 :     std::vector<std::vector<int>> envelope;
     964             :     std::vector<std::string> array =
     965          42 :         Split(CPLGetXMLValue(node, "low", ""), " ", swap_the_first_two);
     966          42 :     std::vector<int> lows;
     967          66 :     for (unsigned int i = 0; i < array.size(); ++i)
     968             :     {
     969          45 :         lows.push_back(atoi(array[i].c_str()));
     970             :     }
     971          21 :     envelope.push_back(std::move(lows));
     972          21 :     array = Split(CPLGetXMLValue(node, "high", ""), " ", swap_the_first_two);
     973          42 :     std::vector<int> highs;
     974          66 :     for (unsigned int i = 0; i < array.size(); ++i)
     975             :     {
     976          45 :         highs.push_back(atoi(array[i].c_str()));
     977             :     }
     978          21 :     envelope.push_back(std::move(highs));
     979          42 :     return envelope;
     980             : }
     981             : 
     982          57 : std::vector<std::string> ParseBoundingBox(CPLXMLNode *node)
     983             : {
     984          57 :     std::vector<std::string> bbox;
     985         171 :     std::string lc = CPLGetXMLValue(node, "lowerCorner", ""), uc;
     986          57 :     if (lc == "")
     987             :     {
     988           0 :         lc = CPLGetXMLValue(node, "LowerCorner", "");
     989             :     }
     990          57 :     if (lc == "")
     991             :     {
     992           0 :         for (CPLXMLNode *n = node->psChild; n != nullptr; n = n->psNext)
     993             :         {
     994           0 :             if (n->eType != CXT_Element || !EQUAL(n->pszValue, "pos"))
     995             :             {
     996           0 :                 continue;
     997             :             }
     998           0 :             if (lc == "")
     999             :             {
    1000           0 :                 lc = CPLGetXMLValue(node, nullptr, "");
    1001             :             }
    1002             :             else
    1003             :             {
    1004           0 :                 uc = CPLGetXMLValue(node, nullptr, "");
    1005             :             }
    1006             :         }
    1007             :     }
    1008             :     else
    1009             :     {
    1010          57 :         uc = CPLGetXMLValue(node, "upperCorner", "");
    1011          57 :         if (uc == "")
    1012             :         {
    1013           0 :             uc = CPLGetXMLValue(node, "UpperCorner", "");
    1014             :         }
    1015             :     }
    1016          57 :     if (lc != "" && uc != "")
    1017             :     {
    1018          57 :         bbox.push_back(lc);
    1019          57 :         bbox.push_back(uc);
    1020             :     }
    1021             :     // time extent if node is an EnvelopeWithTimePeriod
    1022          57 :     lc = CPLGetXMLValue(node, "beginPosition", "");
    1023          57 :     if (lc != "")
    1024             :     {
    1025           0 :         uc = CPLGetXMLValue(node, "endPosition", "");
    1026           0 :         bbox.push_back(lc + "," + uc);
    1027             :     }
    1028         114 :     return bbox;
    1029             : }
    1030             : 
    1031             : }  // namespace WCSUtils

Generated by: LCOV version 1.14