LCOV - code coverage report
Current view: top level - frmts/wcs - wcsutils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 328 477 68.8 %
Date: 2024-11-21 22:18:42 Functions: 29 35 82.9 %

          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.back() == '&')
      58             :     {
      59          96 :         retval.erase(retval.size() - 1);
      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 = CPLGetDirname(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 = CPLFormFilename(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 = CPLFormFilename(dir, subdir.c_str(), nullptr);
     410             :             }
     411             :         }
     412           1 :         cache = CPLFormFilename(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             :             std::string filepath =
     429           0 :                 CPLFormFilename(cache.c_str(), folder[i], nullptr);
     430           0 :             remove(filepath.c_str());
     431             :         }
     432           0 :         CSLDestroy(folder);
     433             :     }
     434             :     // make sure the index exists and is writable
     435         194 :     std::string db = CPLFormFilename(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 : static bool CompareStrings(const std::string &a, const std::string &b)
     461             : {
     462           0 :     return a.compare(b) < 0;
     463             : }
     464             : 
     465           0 : std::vector<std::string> ReadCache(const std::string &cache)
     466             : {
     467           0 :     std::vector<std::string> contents;
     468           0 :     std::string db = CPLFormFilename(cache.c_str(), "db", nullptr);
     469           0 :     char **data = CSLLoad(db.c_str());
     470           0 :     if (data)
     471             :     {
     472           0 :         for (int i = 0; data[i]; ++i)
     473             :         {
     474           0 :             char *val = strchr(data[i], '=');
     475           0 :             if (val != nullptr && *val == '=')
     476             :             {
     477           0 :                 val += 1;
     478           0 :                 if (strcmp(val, "bar") != 0)
     479             :                 {
     480           0 :                     contents.push_back(val);
     481             :                 }
     482             :             }
     483             :         }
     484           0 :         CSLDestroy(data);
     485             :     }
     486           0 :     std::sort(contents.begin(), contents.end(), CompareStrings);
     487           0 :     return contents;
     488             : }
     489             : 
     490             : /* -------------------------------------------------------------------- */
     491             : /*      DeleteEntryFromCache                                            */
     492             : /*      Examines the 'db' file in the cache, which contains             */
     493             : /*      unique key=value pairs, one per line. This function             */
     494             : /*      deletes pairs based on the given key and/or value.              */
     495             : /*      If key or value is empty it is not considered.                  */
     496             : /*      The key is taken as a basename of a file in the cache           */
     497             : /*      and all files with the basename is deleted.                     */
     498             : /* -------------------------------------------------------------------- */
     499             : 
     500           0 : bool DeleteEntryFromCache(const std::string &cache, const std::string &key,
     501             :                           const std::string &value)
     502             : {
     503             :     // Depending on which one of key and value is not "" delete the relevant
     504             :     // entry.
     505           0 :     std::string db = CPLFormFilename(cache.c_str(), "db", nullptr);
     506             :     char **data =
     507           0 :         CSLLoad(db.c_str());  // returns NULL in error and for empty files
     508           0 :     char **data2 = CSLAddNameValue(nullptr, "foo", "bar");
     509           0 :     std::string filename = "";
     510           0 :     if (data)
     511             :     {
     512           0 :         for (int i = 0; data[i]; ++i)
     513             :         {
     514           0 :             char *val = strchr(data[i], '=');
     515           0 :             if (val != nullptr && *val == '=')
     516             :             {
     517           0 :                 *val = '\0';
     518           0 :                 val = val + 1;
     519           0 :                 if ((key != "" && key == data[i]) ||
     520           0 :                     (value != "" && value == val) ||
     521           0 :                     (strcmp(data[i], "foo") == 0))
     522             :                 {
     523           0 :                     if (key != "")
     524             :                     {
     525           0 :                         filename = data[i];
     526             :                     }
     527           0 :                     else if (value != "")
     528             :                     {
     529           0 :                         filename = data[i];
     530             :                     }
     531           0 :                     continue;
     532             :                 }
     533           0 :                 data2 = CSLAddNameValue(data2, data[i], val);
     534             :             }
     535             :         }
     536           0 :         CSLDestroy(data);
     537             :     }
     538           0 :     CSLSave(data2, db.c_str());  // returns 0 in error and for empty arrays
     539           0 :     CSLDestroy(data2);
     540           0 :     if (filename != "")
     541             :     {
     542           0 :         char **folder = VSIReadDir(cache.c_str());
     543           0 :         int size = folder ? CSLCount(folder) : 0;
     544           0 :         for (int i = 0; i < size; i++)
     545             :         {
     546           0 :             if (folder[i][0] == '.')
     547             :             {
     548           0 :                 continue;
     549             :             }
     550           0 :             std::string name = folder[i];
     551           0 :             if (name.find(filename) != std::string::npos)
     552             :             {
     553             :                 std::string filepath =
     554           0 :                     CPLFormFilename(cache.c_str(), name.c_str(), nullptr);
     555           0 :                 if (VSIUnlink(filepath.c_str()) == -1)
     556             :                 {
     557             :                     // error but can't do much, raise a warning?
     558             :                 }
     559             :             }
     560             :         }
     561           0 :         CSLDestroy(folder);
     562             :     }
     563           0 :     return true;
     564             : }
     565             : 
     566             : /* -------------------------------------------------------------------- */
     567             : /*      SearchCache                                                     */
     568             : /*      The key,value pairs in the cache index file 'db' is searched    */
     569             : /*      for the first pair where the value is the given url. If one     */
     570             : /*      is found, the filename is formed from the cache directory name, */
     571             : /*      the key, and the ext.                                           */
     572             : /* -------------------------------------------------------------------- */
     573             : 
     574         144 : CPLErr SearchCache(const std::string &cache, const std::string &url,
     575             :                    std::string &filename, const std::string &ext, bool &found)
     576             : {
     577         144 :     found = false;
     578         288 :     std::string db = CPLFormFilename(cache.c_str(), "db", nullptr);
     579         144 :     VSILFILE *f = VSIFOpenL(db.c_str(), "r");
     580         144 :     if (!f)
     581             :     {
     582           0 :         CPLError(CE_Failure, CPLE_FileIO, "Can't open file '%s': %i\n",
     583           0 :                  db.c_str(), errno);
     584           0 :         return CE_Failure;
     585             :     }
     586         216 :     while (const char *line = CPLReadLineL(f))
     587             :     {
     588         144 :         char *value = strchr((char *)line, '=');
     589         144 :         if (value == nullptr || *value != '=')
     590             :         {
     591           0 :             continue;
     592             :         }
     593         144 :         *value = '\0';
     594         144 :         if (url == (value + 1))
     595             :         {
     596          72 :             filename = line;
     597          72 :             found = true;
     598          72 :             break;
     599             :         }
     600          72 :     }
     601         144 :     VSIFCloseL(f);
     602         144 :     if (found)
     603             :     {
     604             :         filename =
     605          72 :             CPLFormFilename(cache.c_str(), (filename + ext).c_str(), nullptr);
     606          72 :         found = FileIsReadable(filename);
     607             :         // if not readable, we should delete the entry
     608             :     }
     609         144 :     return CE_None;
     610             : }
     611             : 
     612             : /* -------------------------------------------------------------------- */
     613             : /*      AddEntryToCache                                                 */
     614             : /*      A new unique key is created into the database based on the      */
     615             : /*      filename replacing X with a random ascii character.             */
     616             : /*      The returned filename is a path formed from the cache directory */
     617             : /*      name, the filename, and the ext.                                */
     618             : /* -------------------------------------------------------------------- */
     619             : 
     620          48 : CPLErr AddEntryToCache(const std::string &cache, const std::string &url,
     621             :                        std::string &filename, const std::string &ext)
     622             : {
     623             :     // todo: check for lock and do something if locked(?)
     624             :     // todo: lock the cache
     625             :     // assuming the url is not in the cache
     626          96 :     const std::string store = filename;
     627          96 :     const std::string db = CPLFormFilename(cache.c_str(), "db", nullptr);
     628          48 :     VSILFILE *f = VSIFOpenL(db.c_str(), "a");
     629          48 :     if (!f)
     630             :     {
     631           0 :         CPLError(CE_Failure, CPLE_FileIO, "Can't open file '%s': %i\n",
     632           0 :                  db.c_str(), errno);
     633           0 :         return CE_Failure;
     634             :     }
     635             : 
     636             :     // create a new file into the cache using filename as template
     637         144 :     std::string path = "";
     638             :     VSIStatBufL stat;
     639          24 :     do
     640             :     {
     641          72 :         filename = store;
     642             :         static const char chars[] =
     643             :             "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
     644         432 :         for (size_t i = 0; i < filename.length(); ++i)
     645             :         {
     646         360 :             if (filename.at(i) == 'X')
     647             :             {
     648             :                 // coverity[dont_call]
     649         360 :                 filename.replace(i, 1, 1, chars[rand() % (sizeof(chars) - 1)]);
     650             :             }
     651             :         }
     652             :         // replace X with random character from a-zA-Z
     653             :         path =
     654          72 :             CPLFormFilename(cache.c_str(), (filename + ext).c_str(), nullptr);
     655          72 :     } while (VSIStatExL(path.c_str(), &stat, VSI_STAT_EXISTS_FLAG) == 0);
     656          48 :     VSILFILE *f2 = VSIFOpenL(path.c_str(), "w");
     657          48 :     if (f2)
     658             :     {
     659          48 :         VSIFCloseL(f2);
     660             :     }
     661             : 
     662             :     std::string entry =
     663          96 :         filename + "=" + url + "\n";  // '=' for compatibility with CSL
     664          48 :     VSIFWriteL(entry.c_str(), sizeof(char), entry.size(), f);
     665          48 :     VSIFCloseL(f);
     666             : 
     667          48 :     filename = std::move(path);
     668          48 :     return CE_None;
     669             : }
     670             : 
     671             : // steps into element 'from' and adds values of elements 'keys' into the
     672             : // metadata 'path' is the key that is used for metadata and it is appended with
     673             : // 'from' path may be later used to get metadata from elements below 'from' so
     674             : // it is returned in the appended form
     675         134 : CPLXMLNode *AddSimpleMetaData(char ***metadata, CPLXMLNode *node,
     676             :                               std::string &path, const std::string &from,
     677             :                               const std::vector<std::string> &keys)
     678             : {
     679         134 :     CPLXMLNode *node2 = CPLGetXMLNode(node, from.c_str());
     680         134 :     if (node2)
     681             :     {
     682         134 :         path = path + from + ".";
     683         556 :         for (unsigned int i = 0; i < keys.size(); i++)
     684             :         {
     685         422 :             CPLXMLNode *node3 = CPLGetXMLNode(node2, keys[i].c_str());
     686         422 :             if (node3)
     687             :             {
     688         512 :                 const std::string name = path + keys[i];
     689         256 :                 CPLString value = CPLGetXMLValue(node3, nullptr, "");
     690         256 :                 value.Trim();
     691         256 :                 *metadata =
     692         256 :                     CSLSetNameValue(*metadata, name.c_str(), value.c_str());
     693             :             }
     694             :         }
     695             :     }
     696         134 :     return node2;
     697             : }
     698             : 
     699         211 : std::string GetKeywords(CPLXMLNode *root, const std::string &path,
     700             :                         const std::string &kw)
     701             : {
     702         211 :     std::string words = "";
     703             :     CPLXMLNode *keywords =
     704         211 :         (path != "") ? CPLGetXMLNode(root, path.c_str()) : root;
     705         211 :     if (keywords)
     706             :     {
     707         262 :         std::vector<unsigned int> epsg_codes;
     708       36077 :         for (CPLXMLNode *node = keywords->psChild; node != nullptr;
     709       35946 :              node = node->psNext)
     710             :         {
     711       35946 :             if (node->eType != CXT_Element)
     712             :             {
     713           6 :                 continue;
     714             :             }
     715       35940 :             if (kw == node->pszValue)
     716             :             {
     717       35886 :                 CPLString word = CPLGetXMLValue(node, nullptr, "");
     718       17943 :                 word.Trim();
     719             : 
     720             :                 // crs, replace "http://www.opengis.net/def/crs/EPSG/0/"
     721             :                 // or "urn:ogc:def:crs:EPSG::" with EPSG:
     722       17943 :                 const char *const epsg[] = {
     723             :                     "http://www.opengis.net/def/crs/EPSG/0/",
     724             :                     "urn:ogc:def:crs:EPSG::"};
     725       53829 :                 for (unsigned int i = 0; i < CPL_ARRAYSIZE(epsg); i++)
     726             :                 {
     727       35886 :                     size_t pos = word.find(epsg[i]);
     728       35886 :                     if (pos == 0)
     729             :                     {
     730             :                         std::string code =
     731       17564 :                             word.substr(strlen(epsg[i]), std::string::npos);
     732       17564 :                         if (code.find_first_not_of(DIGITS) == std::string::npos)
     733             :                         {
     734       17564 :                             epsg_codes.push_back(atoi(code.c_str()));
     735       17564 :                             continue;
     736             :                         }
     737             :                     }
     738             :                 }
     739             : 
     740             :                 // profiles, remove http://www.opengis.net/spec/
     741             :                 // interpolation, remove
     742             :                 // http://www.opengis.net/def/interpolation/OGC/1/
     743             : 
     744       17943 :                 const char *const spec[] = {
     745             :                     "http://www.opengis.net/spec/",
     746             :                     "http://www.opengis.net/def/interpolation/OGC/1/"};
     747       53829 :                 for (unsigned int i = 0; i < CPL_ARRAYSIZE(spec); i++)
     748             :                 {
     749       35886 :                     size_t pos = word.find(spec[i]);
     750       35886 :                     if (pos != std::string::npos)
     751             :                     {
     752         118 :                         word.erase(pos, strlen(spec[i]));
     753             :                     }
     754             :                 }
     755             : 
     756       17943 :                 if (words != "")
     757             :                 {
     758       17881 :                     words += ",";
     759             :                 }
     760       17943 :                 words += word;
     761             :             }
     762             :         }
     763         131 :         if (epsg_codes.size() > 0)
     764             :         {
     765           8 :             std::string codes;
     766           8 :             std::sort(epsg_codes.begin(), epsg_codes.end());
     767           8 :             unsigned int pajazzo = 0, i = 0, a = 0, b = 0;
     768             :             while (1)
     769             :             {
     770             :                 // cppcheck-suppress containerOutOfBounds
     771       17572 :                 unsigned int c = i < epsg_codes.size() ? epsg_codes[i] : 0;
     772       17572 :                 if (pajazzo == 1)
     773             :                 {
     774        1967 :                     if (c > a + 1)
     775             :                     {
     776        1194 :                         if (codes != "")
     777             :                         {
     778        1189 :                             codes += ",";
     779             :                         }
     780        1194 :                         codes += CPLString().Printf("%i", a);
     781        1194 :                         a = c;
     782             :                     }
     783         773 :                     else if (c >= a)
     784             :                     {
     785         765 :                         b = c;
     786         765 :                         pajazzo = 2;
     787             :                     }
     788             :                 }
     789       15605 :                 else if (pajazzo == 2)
     790             :                 {
     791       15597 :                     if (c > b + 1)
     792             :                     {
     793         765 :                         if (codes != "")
     794             :                         {
     795         762 :                             codes += ",";
     796             :                         }
     797         765 :                         codes += CPLString().Printf("%i:%i", a, b);
     798         765 :                         a = c;
     799         765 :                         pajazzo = 1;
     800             :                     }
     801       14832 :                     else if (c >= b)
     802             :                     {
     803       14832 :                         b = c;
     804             :                     }
     805             :                 }
     806             :                 else
     807             :                 {  // pajazzo == 0
     808           8 :                     a = c;
     809           8 :                     pajazzo = 1;
     810             :                 }
     811       17572 :                 if (i == epsg_codes.size())
     812             :                 {
     813             :                     // must empty the pajazzo before leaving
     814           8 :                     if (codes != "")
     815             :                     {
     816           8 :                         codes += ",";
     817             :                     }
     818           8 :                     if (pajazzo == 1)
     819             :                     {
     820           8 :                         codes += CPLString().Printf("%i", a);
     821             :                     }
     822           0 :                     else if (pajazzo == 2)
     823             :                     {
     824           0 :                         codes += CPLString().Printf("%i:%i", a, b);
     825             :                     }
     826           8 :                     break;
     827             :                 }
     828       17564 :                 ++i;
     829       17564 :             }
     830           8 :             if (words != "")
     831             :             {
     832           8 :                 words += ",";
     833             :             }
     834           8 :             words += "EPSG:" + codes;
     835             :         }
     836             :     }
     837         211 :     return words;
     838             : }
     839             : 
     840         147 : std::string ParseCRS(CPLXMLNode *node)
     841             : {
     842             :     // test for attrs crs (OWS) and srsName (GML), and text contents of subnode
     843             :     // (GridBaseCRS)
     844         147 :     std::string crs = CPLGetXMLValue(node, "crs", "");
     845         147 :     if (crs == "")
     846             :     {
     847          57 :         crs = CPLGetXMLValue(node, "srsName", "");
     848          57 :         if (crs == "")
     849             :         {
     850          36 :             crs = CPLGetXMLValue(node, "GridBaseCRS", "");
     851             :         }
     852             :     }
     853         147 :     if (crs == "")
     854             :     {
     855           0 :         return crs;
     856             :     }
     857             :     // split compound names
     858             :     // see for example
     859             :     // http://www.eurogeographics.org/sites/default/files/2016-01-18_INSPIRE-KEN-CovFaq.pdf
     860         147 :     size_t pos = crs.find("?");
     861         147 :     if (pos != std::string::npos)
     862             :     {
     863           3 :         if (crs.find("crs-compound?") != std::string::npos)
     864             :         {  // 1=uri&2=uri...
     865             :             // assuming the first is for X,Y
     866           3 :             crs = crs.substr(pos + 1);
     867           3 :             pos = crs.find("&");
     868           3 :             if (pos != std::string::npos)
     869             :             {
     870           3 :                 pos = pos - 2;
     871             :             }
     872           3 :             crs = crs.substr(2, pos);
     873             :         }
     874             :     }
     875         147 :     return crs;
     876             : }
     877             : 
     878             : // if appropriate, try to create WKT description from CRS name
     879             : // return false if failure
     880             : // appropriate means, that the name is a real CRS
     881          57 : bool CRS2Projection(const std::string &crs, OGRSpatialReference *sr,
     882             :                     char **projection)
     883             : {
     884          57 :     if (*projection != nullptr)
     885             :     {
     886           0 :         CPLFree(*projection);
     887             :     }
     888          57 :     *projection = nullptr;
     889          57 :     if (crs.empty())
     890             :     {
     891           0 :         return true;
     892             :     }
     893         114 :     if (crs.find(":imageCRS") != std::string::npos ||
     894         114 :         crs.find("/Index1D") != std::string::npos ||
     895         114 :         crs.find("/Index2D") != std::string::npos ||
     896         171 :         crs.find("/Index3D") != std::string::npos ||
     897          57 :         crs.find("/AnsiDate") != std::string::npos)
     898             :     {
     899             :         // not a map projection
     900           0 :         return true;
     901             :     }
     902         114 :     std::string crs2 = crs;
     903             :     // rasdaman uses urls, which return gml:ProjectedCRS XML, which is not
     904             :     // recognized by GDAL currently
     905          57 :     if (crs2.find("EPSG") != std::string::npos)
     906             :     {  // ...EPSG...(\d+)
     907          57 :         size_t pos1 = crs2.find_last_of(DIGITS);
     908          57 :         if (pos1 != std::string::npos)
     909             :         {
     910          57 :             size_t pos2 = pos1 - 1;
     911          57 :             char c = crs2.at(pos2);
     912         231 :             while (strchr(DIGITS, c))
     913             :             {
     914         174 :                 pos2 = pos2 - 1;
     915         174 :                 c = crs2.at(pos2);
     916             :             }
     917          57 :             crs2 = "EPSGA:" + crs2.substr(pos2 + 1, pos1 - pos2);
     918             :         }
     919             :     }
     920         114 :     OGRSpatialReference local_sr;
     921          57 :     OGRSpatialReference *sr_pointer = sr != nullptr ? sr : &local_sr;
     922          57 :     if (sr_pointer->SetFromUserInput(
     923             :             crs2.c_str(),
     924          57 :             OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) ==
     925             :         OGRERR_NONE)
     926             :     {
     927          57 :         sr_pointer->exportToWkt(projection);
     928          57 :         return true;
     929             :     }
     930           0 :     return false;
     931             : }
     932             : 
     933          57 : bool CRSImpliesAxisOrderSwap(const std::string &crs, bool &swap,
     934             :                              char **projection)
     935             : {
     936         114 :     OGRSpatialReference oSRS;
     937          57 :     char *tmp = nullptr;
     938          57 :     swap = false;
     939          57 :     if (!CRS2Projection(crs, &oSRS, &tmp))
     940             :     {
     941           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     942             :                  "Unable to interpret coverage CRS '%s'.", crs.c_str());
     943           0 :         CPLFree(tmp);
     944           0 :         return false;
     945             :     }
     946          57 :     if (tmp)
     947             :     {
     948          57 :         if (projection != nullptr)
     949             :         {
     950          57 :             *projection = tmp;
     951             :         }
     952             :         else
     953             :         {
     954           0 :             CPLFree(tmp);
     955             :         }
     956          57 :         swap = oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting();
     957             :     }
     958          57 :     return true;
     959             : }
     960             : 
     961          21 : std::vector<std::vector<int>> ParseGridEnvelope(CPLXMLNode *node,
     962             :                                                 bool swap_the_first_two)
     963             : {
     964          21 :     std::vector<std::vector<int>> envelope;
     965             :     std::vector<std::string> array =
     966          42 :         Split(CPLGetXMLValue(node, "low", ""), " ", swap_the_first_two);
     967          42 :     std::vector<int> lows;
     968          66 :     for (unsigned int i = 0; i < array.size(); ++i)
     969             :     {
     970          45 :         lows.push_back(atoi(array[i].c_str()));
     971             :     }
     972          21 :     envelope.push_back(lows);
     973          21 :     array = Split(CPLGetXMLValue(node, "high", ""), " ", swap_the_first_two);
     974          42 :     std::vector<int> highs;
     975          66 :     for (unsigned int i = 0; i < array.size(); ++i)
     976             :     {
     977          45 :         highs.push_back(atoi(array[i].c_str()));
     978             :     }
     979          21 :     envelope.push_back(highs);
     980          42 :     return envelope;
     981             : }
     982             : 
     983          57 : std::vector<std::string> ParseBoundingBox(CPLXMLNode *node)
     984             : {
     985          57 :     std::vector<std::string> bbox;
     986         171 :     std::string lc = CPLGetXMLValue(node, "lowerCorner", ""), uc;
     987          57 :     if (lc == "")
     988             :     {
     989           0 :         lc = CPLGetXMLValue(node, "LowerCorner", "");
     990             :     }
     991          57 :     if (lc == "")
     992             :     {
     993           0 :         for (CPLXMLNode *n = node->psChild; n != nullptr; n = n->psNext)
     994             :         {
     995           0 :             if (n->eType != CXT_Element || !EQUAL(n->pszValue, "pos"))
     996             :             {
     997           0 :                 continue;
     998             :             }
     999           0 :             if (lc == "")
    1000             :             {
    1001           0 :                 lc = CPLGetXMLValue(node, nullptr, "");
    1002             :             }
    1003             :             else
    1004             :             {
    1005           0 :                 uc = CPLGetXMLValue(node, nullptr, "");
    1006             :             }
    1007             :         }
    1008             :     }
    1009             :     else
    1010             :     {
    1011          57 :         uc = CPLGetXMLValue(node, "upperCorner", "");
    1012          57 :         if (uc == "")
    1013             :         {
    1014           0 :             uc = CPLGetXMLValue(node, "UpperCorner", "");
    1015             :         }
    1016             :     }
    1017          57 :     if (lc != "" && uc != "")
    1018             :     {
    1019          57 :         bbox.push_back(lc);
    1020          57 :         bbox.push_back(uc);
    1021             :     }
    1022             :     // time extent if node is an EnvelopeWithTimePeriod
    1023          57 :     lc = CPLGetXMLValue(node, "beginPosition", "");
    1024          57 :     if (lc != "")
    1025             :     {
    1026           0 :         uc = CPLGetXMLValue(node, "endPosition", "");
    1027           0 :         bbox.push_back(lc + "," + uc);
    1028             :     }
    1029         114 :     return bbox;
    1030             : }
    1031             : 
    1032             : }  // namespace WCSUtils

Generated by: LCOV version 1.14