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

Generated by: LCOV version 1.14