LCOV - code coverage report
Current view: top level - ogr - ogr_srsnode.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 195 230 84.8 %
Date: 2024-05-03 15:49:35 Functions: 21 23 91.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGR_SRSNode class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_port.h"
      31             : #include "ogr_spatialref.h"
      32             : 
      33             : #include <cctype>
      34             : #include <cstddef>
      35             : #include <cstring>
      36             : 
      37             : #include "ogr_core.h"
      38             : #include "ogr_p.h"
      39             : #include "cpl_conv.h"
      40             : #include "cpl_error.h"
      41             : #include "cpl_string.h"
      42             : 
      43             : /************************************************************************/
      44             : /*                            OGR_SRSNode()                             */
      45             : /************************************************************************/
      46             : 
      47             : /**
      48             :  * Constructor.
      49             :  *
      50             :  * @param pszValueIn this optional parameter can be used to initialize
      51             :  * the value of the node upon creation.  If omitted the node will be created
      52             :  * with a value of "".  Newly created OGR_SRSNodes have no children.
      53             :  */
      54             : 
      55      855616 : OGR_SRSNode::OGR_SRSNode(const char *pszValueIn)
      56      855616 :     : pszValue(CPLStrdup(pszValueIn)), papoChildNodes(nullptr),
      57      855616 :       poParent(nullptr), nChildren(0)
      58             : {
      59      855616 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                            ~OGR_SRSNode()                            */
      63             : /************************************************************************/
      64             : 
      65      829957 : OGR_SRSNode::~OGR_SRSNode()
      66             : 
      67             : {
      68      829957 :     CPLFree(pszValue);
      69             : 
      70      829957 :     ClearChildren();
      71      829957 : }
      72             : 
      73             : /************************************************************************/
      74             : /*                             ~Listener()                              */
      75             : /************************************************************************/
      76             : 
      77             : OGR_SRSNode::Listener::~Listener() = default;
      78             : 
      79             : /************************************************************************/
      80             : /*                           RegisterListener()                         */
      81             : /************************************************************************/
      82             : 
      83       21001 : void OGR_SRSNode::RegisterListener(const std::shared_ptr<Listener> &listener)
      84             : {
      85       21001 :     m_listener = listener;
      86       21001 : }
      87             : 
      88             : /************************************************************************/
      89             : /*                             notifyChange()                           */
      90             : /************************************************************************/
      91             : 
      92     1668000 : void OGR_SRSNode::notifyChange()
      93             : {
      94     3336000 :     auto locked = m_listener.lock();
      95     1668000 :     if (locked)
      96             :     {
      97     1643620 :         locked->notifyChange(this);
      98             :     }
      99     1668000 : }
     100             : 
     101             : /************************************************************************/
     102             : /*                           ClearChildren()                            */
     103             : /************************************************************************/
     104             : 
     105             : /** Clear children nodes
     106             :  */
     107     1662920 : void OGR_SRSNode::ClearChildren()
     108             : 
     109             : {
     110     2471760 :     for (int i = 0; i < nChildren; i++)
     111             :     {
     112      808847 :         delete papoChildNodes[i];
     113             :     }
     114             : 
     115     1662920 :     CPLFree(papoChildNodes);
     116             : 
     117     1662920 :     papoChildNodes = nullptr;
     118     1662920 :     nChildren = 0;
     119     1662920 : }
     120             : 
     121             : /************************************************************************/
     122             : /*                           GetChildCount()                            */
     123             : /************************************************************************/
     124             : 
     125             : /**
     126             :  * \fn int OGR_SRSNode::GetChildCount() const;
     127             :  *
     128             :  * Get number of children nodes.
     129             :  *
     130             :  * @return 0 for leaf nodes, or the number of children nodes.
     131             :  */
     132             : 
     133             : /************************************************************************/
     134             : /*                              GetChild()                              */
     135             : /************************************************************************/
     136             : 
     137             : /**
     138             :  * Fetch requested child.
     139             :  *
     140             :  * @param iChild the index of the child to fetch, from 0 to
     141             :  * GetChildCount() - 1.
     142             :  *
     143             :  * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
     144             :  * child.
     145             :  */
     146             : 
     147       34198 : OGR_SRSNode *OGR_SRSNode::GetChild(int iChild)
     148             : 
     149             : {
     150       34198 :     if (iChild < 0 || iChild >= nChildren)
     151           0 :         return nullptr;
     152             : 
     153       34198 :     return papoChildNodes[iChild];
     154             : }
     155             : 
     156             : /**
     157             :  * Fetch requested child.
     158             :  *
     159             :  * @param iChild the index of the child to fetch, from 0 to
     160             :  * GetChildCount() - 1.
     161             :  *
     162             :  * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
     163             :  * child.
     164             :  */
     165             : 
     166      147217 : const OGR_SRSNode *OGR_SRSNode::GetChild(int iChild) const
     167             : 
     168             : {
     169      147217 :     if (iChild < 0 || iChild >= nChildren)
     170           0 :         return nullptr;
     171             : 
     172      147217 :     return papoChildNodes[iChild];
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                              GetNode()                               */
     177             : /************************************************************************/
     178             : 
     179             : /**
     180             :  * Find named node in tree.
     181             :  *
     182             :  * This method does a pre-order traversal of the node tree searching for
     183             :  * a node with this exact value (case insensitive), and returns it.  Leaf
     184             :  * nodes are not considered, under the assumption that they are just
     185             :  * attribute value nodes.
     186             :  *
     187             :  * If a node appears more than once in the tree (such as UNIT for instance),
     188             :  * the first encountered will be returned.  Use GetNode() on a subtree to be
     189             :  * more specific.
     190             :  *
     191             :  * @param pszName the name of the node to search for.
     192             :  *
     193             :  * @return a pointer to the node found, or NULL if none.
     194             :  */
     195             : 
     196      553549 : OGR_SRSNode *OGR_SRSNode::GetNode(const char *pszName)
     197             : 
     198             : {
     199      553549 :     if (nChildren > 0 && EQUAL(pszName, pszValue))
     200       30535 :         return this;
     201             : 
     202             :     /* -------------------------------------------------------------------- */
     203             :     /*      First we check the immediate children so we will get an         */
     204             :     /*      immediate child in preference to a subchild.                    */
     205             :     /* -------------------------------------------------------------------- */
     206     1100010 :     for (int i = 0; i < nChildren; i++)
     207             :     {
     208      619117 :         if (EQUAL(papoChildNodes[i]->pszValue, pszName) &&
     209       42117 :             papoChildNodes[i]->nChildren > 0)
     210       42117 :             return papoChildNodes[i];
     211             :     }
     212             : 
     213             :     /* -------------------------------------------------------------------- */
     214             :     /*      Then get each child to check their children.                    */
     215             :     /* -------------------------------------------------------------------- */
     216      937494 :     for (int i = 0; i < nChildren; i++)
     217             :     {
     218      466638 :         OGR_SRSNode *poNode = papoChildNodes[i]->GetNode(pszName);
     219      466638 :         if (poNode != nullptr)
     220       10041 :             return poNode;
     221             :     }
     222             : 
     223      470856 :     return nullptr;
     224             : }
     225             : 
     226             : /**
     227             :  * Find named node in tree.
     228             :  *
     229             :  * This method does a pre-order traversal of the node tree searching for
     230             :  * a node with this exact value (case insensitive), and returns it.  Leaf
     231             :  * nodes are not considered, under the assumption that they are just
     232             :  * attribute value nodes.
     233             :  *
     234             :  * If a node appears more than once in the tree (such as UNIT for instance),
     235             :  * the first encountered will be returned.  Use GetNode() on a subtree to be
     236             :  * more specific.
     237             :  *
     238             :  * @param pszName the name of the node to search for.
     239             :  *
     240             :  * @return a pointer to the node found, or NULL if none.
     241             :  */
     242             : 
     243          93 : const OGR_SRSNode *OGR_SRSNode::GetNode(const char *pszName) const
     244             : 
     245             : {
     246          93 :     return const_cast<OGR_SRSNode *>(this)->GetNode(pszName);
     247             : }
     248             : 
     249             : /************************************************************************/
     250             : /*                              AddChild()                              */
     251             : /************************************************************************/
     252             : 
     253             : /**
     254             :  * Add passed node as a child of target node.
     255             :  *
     256             :  * Note that ownership of the passed node is assumed by the node on which
     257             :  * the method is invoked ... use the Clone() method if the original is to
     258             :  * be preserved.  New children are always added at the end of the list.
     259             :  *
     260             :  * @param poNew the node to add as a child.
     261             :  */
     262             : 
     263      834287 : void OGR_SRSNode::AddChild(OGR_SRSNode *poNew)
     264             : 
     265             : {
     266      834287 :     InsertChild(poNew, nChildren);
     267      834287 : }
     268             : 
     269             : /************************************************************************/
     270             : /*                            InsertChild()                             */
     271             : /************************************************************************/
     272             : 
     273             : /**
     274             :  * Insert the passed node as a child of target node, at the indicated
     275             :  * position.
     276             :  *
     277             :  * Note that ownership of the passed node is assumed by the node on which
     278             :  * the method is invoked ... use the Clone() method if the original is to
     279             :  * be preserved.  All existing children at location iChild and beyond are
     280             :  * push down one space to make space for the new child.
     281             :  *
     282             :  * @param poNew the node to add as a child.
     283             :  * @param iChild position to insert, use 0 to insert at the beginning.
     284             :  */
     285             : 
     286      834293 : void OGR_SRSNode::InsertChild(OGR_SRSNode *poNew, int iChild)
     287             : 
     288             : {
     289      834293 :     if (iChild > nChildren)
     290           0 :         iChild = nChildren;
     291             : 
     292      834293 :     nChildren++;
     293      834293 :     papoChildNodes = static_cast<OGR_SRSNode **>(
     294      834293 :         CPLRealloc(papoChildNodes, sizeof(void *) * nChildren));
     295             : 
     296      834293 :     memmove(papoChildNodes + iChild + 1, papoChildNodes + iChild,
     297      834293 :             sizeof(void *) * (nChildren - iChild - 1));
     298             : 
     299      834293 :     papoChildNodes[iChild] = poNew;
     300      834293 :     poNew->poParent = this;
     301             : 
     302      834293 :     poNew->m_listener = m_listener;
     303      834293 :     notifyChange();
     304      834293 : }
     305             : 
     306             : /************************************************************************/
     307             : /*                            DestroyChild()                            */
     308             : /************************************************************************/
     309             : 
     310             : /**
     311             :  * Remove a child node, and it's subtree.
     312             :  *
     313             :  * Note that removing a child node will result in children after it
     314             :  * being renumbered down one.
     315             :  *
     316             :  * @param iChild the index of the child.
     317             :  */
     318             : 
     319         353 : void OGR_SRSNode::DestroyChild(int iChild)
     320             : 
     321             : {
     322         353 :     if (iChild < 0 || iChild >= nChildren)
     323           0 :         return;
     324             : 
     325         353 :     delete papoChildNodes[iChild];
     326         722 :     while (iChild < nChildren - 1)
     327             :     {
     328         369 :         papoChildNodes[iChild] = papoChildNodes[iChild + 1];
     329         369 :         iChild++;
     330             :     }
     331             : 
     332         353 :     nChildren--;
     333         353 :     notifyChange();
     334             : }
     335             : 
     336             : /************************************************************************/
     337             : /*                             FindChild()                              */
     338             : /************************************************************************/
     339             : 
     340             : /**
     341             :  * Find the index of the child matching the given string.
     342             :  *
     343             :  * Note that the node value must match pszValue with the exception of
     344             :  * case.  The comparison is case insensitive.
     345             :  *
     346             :  * @param pszValueIn the node value being searched for.
     347             :  *
     348             :  * @return the child index, or -1 on failure.
     349             :  */
     350             : 
     351       42591 : int OGR_SRSNode::FindChild(const char *pszValueIn) const
     352             : 
     353             : {
     354      152240 :     for (int i = 0; i < nChildren; i++)
     355             :     {
     356      138887 :         if (EQUAL(papoChildNodes[i]->pszValue, pszValueIn))
     357       29238 :             return i;
     358             :     }
     359             : 
     360       13353 :     return -1;
     361             : }
     362             : 
     363             : /************************************************************************/
     364             : /*                              GetValue()                              */
     365             : /************************************************************************/
     366             : 
     367             : /**
     368             :  * \fn const char *OGR_SRSNode::GetValue() const;
     369             :  *
     370             :  * Fetch value string for this node.
     371             :  *
     372             :  * @return A non-NULL string is always returned.  The returned pointer is to
     373             :  * the internal value of this node, and should not be modified, or freed.
     374             :  */
     375             : 
     376             : /************************************************************************/
     377             : /*                              SetValue()                              */
     378             : /************************************************************************/
     379             : 
     380             : /**
     381             :  * Set the node value.
     382             :  *
     383             :  * @param pszNewValue the new value to assign to this node.  The passed
     384             :  * string is duplicated and remains the responsibility of the caller.
     385             :  */
     386             : 
     387      833353 : void OGR_SRSNode::SetValue(const char *pszNewValue)
     388             : 
     389             : {
     390      833353 :     CPLFree(pszValue);
     391      833353 :     pszValue = CPLStrdup(pszNewValue);
     392      833353 :     notifyChange();
     393      833353 : }
     394             : 
     395             : /************************************************************************/
     396             : /*                               Clone()                                */
     397             : /************************************************************************/
     398             : 
     399             : /**
     400             :  * Make a duplicate of this node, and it's children.
     401             :  *
     402             :  * @return a new node tree, which becomes the responsibility of the caller.
     403             :  */
     404             : 
     405        2561 : OGR_SRSNode *OGR_SRSNode::Clone() const
     406             : 
     407             : {
     408        2561 :     OGR_SRSNode *poNew = new OGR_SRSNode(pszValue);
     409             : 
     410        5060 :     for (int i = 0; i < nChildren; i++)
     411             :     {
     412        2499 :         poNew->AddChild(papoChildNodes[i]->Clone());
     413             :     }
     414        2561 :     poNew->m_listener = m_listener;
     415             : 
     416        2561 :     return poNew;
     417             : }
     418             : 
     419             : /************************************************************************/
     420             : /*                            NeedsQuoting()                            */
     421             : /*                                                                      */
     422             : /*      Does this node need to be quoted when it is exported to Wkt?    */
     423             : /************************************************************************/
     424             : 
     425      257166 : int OGR_SRSNode::NeedsQuoting() const
     426             : 
     427             : {
     428             :     // Non-terminals are never quoted.
     429      257166 :     if (GetChildCount() != 0)
     430       92428 :         return FALSE;
     431             : 
     432             :     // As per bugzilla bug 201, the OGC spec says the authority code
     433             :     // needs to be quoted even though it appears well behaved.
     434      164738 :     if (poParent != nullptr && EQUAL(poParent->GetValue(), "AUTHORITY"))
     435       45944 :         return TRUE;
     436             : 
     437             :     // As per bugzilla bug 294, the OGC spec says the direction
     438             :     // values for the AXIS keywords should *not* be quoted.
     439      145466 :     if (poParent != nullptr && EQUAL(poParent->GetValue(), "AXIS") &&
     440       26672 :         this != poParent->GetChild(0))
     441       13336 :         return FALSE;
     442             : 
     443      105458 :     if (poParent != nullptr && EQUAL(poParent->GetValue(), "CS") &&
     444           0 :         this == poParent->GetChild(0))
     445           0 :         return FALSE;
     446             : 
     447             :     // Strings starting with e or E are not valid numeric values, so they
     448             :     // need quoting, like in AXIS["E",EAST]
     449      105458 :     if ((pszValue[0] == 'e' || pszValue[0] == 'E'))
     450        6842 :         return TRUE;
     451             : 
     452             :     // Non-numeric tokens are generally quoted while clean numeric values
     453             :     // are generally not.
     454      409413 :     for (int i = 0; pszValue[i] != '\0'; i++)
     455             :     {
     456      373422 :         if ((pszValue[i] < '0' || pszValue[i] > '9') && pszValue[i] != '.' &&
     457       62805 :             pszValue[i] != '-' && pszValue[i] != '+' && pszValue[i] != 'e' &&
     458       62625 :             pszValue[i] != 'E')
     459       62625 :             return TRUE;
     460             :     }
     461             : 
     462       35991 :     return FALSE;
     463             : }
     464             : 
     465             : /************************************************************************/
     466             : /*                            exportToWkt()                             */
     467             : /************************************************************************/
     468             : 
     469             : /**
     470             :  * Convert this tree of nodes into WKT format.
     471             :  *
     472             :  * Note that the returned WKT string should be freed with
     473             :  * CPLFree() when no longer needed.  It is the responsibility of the caller.
     474             :  *
     475             :  * @param ppszResult the resulting string is returned in this pointer.
     476             :  *
     477             :  * @return currently OGRERR_NONE is always returned, but the future it
     478             :  * is possible error conditions will develop.
     479             :  */
     480             : 
     481      257094 : OGRErr OGR_SRSNode::exportToWkt(char **ppszResult) const
     482             : 
     483             : {
     484             :     /* -------------------------------------------------------------------- */
     485             :     /*      Build a list of the WKT format for the children.                */
     486             :     /* -------------------------------------------------------------------- */
     487             :     char **papszChildrenWkt =
     488      257094 :         static_cast<char **>(CPLCalloc(sizeof(char *), nChildren + 1));
     489      257094 :     size_t nLength = strlen(pszValue) + 4;
     490             : 
     491      507259 :     for (int i = 0; i < nChildren; i++)
     492             :     {
     493      250165 :         papoChildNodes[i]->exportToWkt(papszChildrenWkt + i);
     494      250165 :         nLength += strlen(papszChildrenWkt[i]) + 1;
     495             :     }
     496             : 
     497             :     /* -------------------------------------------------------------------- */
     498             :     /*      Allocate the result string.                                     */
     499             :     /* -------------------------------------------------------------------- */
     500      257094 :     *ppszResult = static_cast<char *>(CPLMalloc(nLength));
     501      257094 :     *ppszResult[0] = '\0';
     502             : 
     503             :     /* -------------------------------------------------------------------- */
     504             :     /*      Capture this nodes value.  We put it in double quotes if        */
     505             :     /*      this is a leaf node, otherwise we assume it is a well formed    */
     506             :     /*      node name.                                                      */
     507             :     /* -------------------------------------------------------------------- */
     508      257094 :     if (NeedsQuoting())
     509             :     {
     510      115385 :         strcat(*ppszResult, "\"");
     511      115385 :         strcat(*ppszResult, pszValue);  // Should we do quoting?
     512      115385 :         strcat(*ppszResult, "\"");
     513             :     }
     514             :     else
     515      141709 :         strcat(*ppszResult, pszValue);
     516             : 
     517             :     /* -------------------------------------------------------------------- */
     518             :     /*      Add the children strings with appropriate brackets and commas.  */
     519             :     /* -------------------------------------------------------------------- */
     520      257094 :     if (nChildren > 0)
     521       92402 :         strcat(*ppszResult, "[");
     522             : 
     523      507259 :     for (int i = 0; i < nChildren; i++)
     524             :     {
     525      250165 :         strcat(*ppszResult, papszChildrenWkt[i]);
     526      250165 :         if (i == nChildren - 1)
     527       92402 :             strcat(*ppszResult, "]");
     528             :         else
     529      157763 :             strcat(*ppszResult, ",");
     530             :     }
     531             : 
     532      257094 :     CSLDestroy(papszChildrenWkt);
     533             : 
     534      257094 :     return OGRERR_NONE;
     535             : }
     536             : 
     537             : /************************************************************************/
     538             : /*                         exportToPrettyWkt()                          */
     539             : /************************************************************************/
     540             : 
     541             : /**
     542             :  * Convert this tree of nodes into pretty WKT format.
     543             :  *
     544             :  * Note that the returned WKT string should be freed with
     545             :  * CPLFree() when no longer needed.  It is the responsibility of the caller.
     546             :  *
     547             :  * @param ppszResult the resulting string is returned in this pointer.
     548             :  *
     549             :  * @param nDepth depth of the node
     550             :  *
     551             :  * @return currently OGRERR_NONE is always returned, but the future it
     552             :  * is possible error conditions will develop.
     553             :  */
     554             : 
     555          72 : OGRErr OGR_SRSNode::exportToPrettyWkt(char **ppszResult, int nDepth) const
     556             : 
     557             : {
     558             :     /* -------------------------------------------------------------------- */
     559             :     /*      Build a list of the WKT format for the children.                */
     560             :     /* -------------------------------------------------------------------- */
     561             :     char **papszChildrenWkt =
     562          72 :         static_cast<char **>(CPLCalloc(sizeof(char *), nChildren + 1));
     563          72 :     size_t nLength = strlen(pszValue) + 4;
     564             : 
     565         142 :     for (int i = 0; i < nChildren; i++)
     566             :     {
     567          70 :         papoChildNodes[i]->exportToPrettyWkt(papszChildrenWkt + i, nDepth + 1);
     568          70 :         nLength += strlen(papszChildrenWkt[i]) + 2 + nDepth * 4;
     569             :     }
     570             : 
     571             :     /* -------------------------------------------------------------------- */
     572             :     /*      Allocate the result string.                                     */
     573             :     /* -------------------------------------------------------------------- */
     574          72 :     *ppszResult = static_cast<char *>(CPLMalloc(nLength));
     575          72 :     *ppszResult[0] = '\0';
     576             : 
     577             :     /* -------------------------------------------------------------------- */
     578             :     /*      Capture this nodes value.  We put it in double quotes if        */
     579             :     /*      this is a leaf node, otherwise we assume it is a well formed    */
     580             :     /*      node name.                                                      */
     581             :     /* -------------------------------------------------------------------- */
     582          72 :     if (NeedsQuoting())
     583             :     {
     584          26 :         strcat(*ppszResult, "\"");
     585          26 :         strcat(*ppszResult, pszValue);  // Should we do quoting?
     586          26 :         strcat(*ppszResult, "\"");
     587             :     }
     588             :     else
     589             :     {
     590          46 :         strcat(*ppszResult, pszValue);
     591             :     }
     592             : 
     593             :     /* -------------------------------------------------------------------- */
     594             :     /*      Add the children strings with appropriate brackets and commas.  */
     595             :     /* -------------------------------------------------------------------- */
     596          72 :     if (nChildren > 0)
     597          26 :         strcat(*ppszResult, "[");
     598             : 
     599         142 :     for (int i = 0; i < nChildren; i++)
     600             :     {
     601          70 :         if (papoChildNodes[i]->GetChildCount() > 0)
     602             :         {
     603          24 :             strcat(*ppszResult, "\n");
     604         160 :             for (int j = 0; j < 4 * nDepth; j++)
     605         136 :                 strcat(*ppszResult, " ");
     606             :         }
     607          70 :         strcat(*ppszResult, papszChildrenWkt[i]);
     608          70 :         if (i < nChildren - 1)
     609          44 :             strcat(*ppszResult, ",");
     610             :     }
     611             : 
     612          72 :     if (nChildren > 0)
     613             :     {
     614          26 :         if ((*ppszResult)[strlen(*ppszResult) - 1] == ',')
     615           0 :             (*ppszResult)[strlen(*ppszResult) - 1] = '\0';
     616             : 
     617          26 :         strcat(*ppszResult, "]");
     618             :     }
     619             : 
     620          72 :     CSLDestroy(papszChildrenWkt);
     621             : 
     622          72 :     return OGRERR_NONE;
     623             : }
     624             : 
     625             : /************************************************************************/
     626             : /*                           importFromWkt()                            */
     627             : /************************************************************************/
     628             : 
     629             : /**
     630             :  * Import from WKT string.
     631             :  *
     632             :  * This method will wipe the existing children and value of this node, and
     633             :  * reassign them based on the contents of the passed WKT string.  Only as
     634             :  * much of the input string as needed to construct this node, and its
     635             :  * children is consumed from the input string, and the input string pointer
     636             :  * is then updated to point to the remaining (unused) input.
     637             :  *
     638             :  * @param ppszInput Pointer to pointer to input.  The pointer is updated to
     639             :  * point to remaining unused input text.
     640             :  *
     641             :  * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
     642             :  * fails for any reason.
     643             :  * @deprecated GDAL 2.3. Use importFromWkt(const char**) instead.
     644             :  */
     645             : 
     646           0 : OGRErr OGR_SRSNode::importFromWkt(char **ppszInput)
     647             : 
     648             : {
     649           0 :     int nNodes = 0;
     650           0 :     return importFromWkt(const_cast<const char **>(ppszInput), 0, &nNodes);
     651             : }
     652             : 
     653             : /**
     654             :  * Import from WKT string.
     655             :  *
     656             :  * This method will wipe the existing children and value of this node, and
     657             :  * reassign them based on the contents of the passed WKT string.  Only as
     658             :  * much of the input string as needed to construct this node, and its
     659             :  * children is consumed from the input string, and the input string pointer
     660             :  * is then updated to point to the remaining (unused) input.
     661             :  *
     662             :  * @param ppszInput Pointer to pointer to input.  The pointer is updated to
     663             :  * point to remaining unused input text.
     664             :  *
     665             :  * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
     666             :  * fails for any reason.
     667             :  *
     668             :  * @since GDAL 2.3
     669             :  */
     670             : 
     671       21288 : OGRErr OGR_SRSNode::importFromWkt(const char **ppszInput)
     672             : 
     673             : {
     674       21288 :     int nNodes = 0;
     675       42576 :     return importFromWkt(ppszInput, 0, &nNodes);
     676             : }
     677             : 
     678      832958 : OGRErr OGR_SRSNode::importFromWkt(const char **ppszInput, int nRecLevel,
     679             :                                   int *pnNodes)
     680             : 
     681             : {
     682             :     // Sanity checks.
     683      832958 :     if (nRecLevel == 10)
     684             :     {
     685           0 :         return OGRERR_CORRUPT_DATA;
     686             :     }
     687      832958 :     if (*pnNodes == 1000)
     688             :     {
     689           0 :         return OGRERR_CORRUPT_DATA;
     690             :     }
     691             : 
     692      832958 :     const char *pszInput = *ppszInput;
     693      832958 :     bool bInQuotedString = false;
     694             : 
     695             :     /* -------------------------------------------------------------------- */
     696             :     /*      Clear any existing children of this node.                       */
     697             :     /* -------------------------------------------------------------------- */
     698      832958 :     ClearChildren();
     699             : 
     700             :     /* -------------------------------------------------------------------- */
     701             :     /*      Read the ``value'' for this node.                               */
     702             :     /* -------------------------------------------------------------------- */
     703             :     {
     704             :         char szToken[512];  // do not initialize whole buffer. significant
     705             :                             // overhead
     706      832958 :         size_t nTokenLen = 0;
     707      832958 :         szToken[0] = '\0';
     708             : 
     709     7660420 :         while (*pszInput != '\0' && nTokenLen + 1 < sizeof(szToken))
     710             :         {
     711     7660420 :             if (*pszInput == '"')
     712             :             {
     713      736324 :                 bInQuotedString = !bInQuotedString;
     714             :             }
     715     6924100 :             else if (!bInQuotedString &&
     716     3992420 :                      (*pszInput == '[' || *pszInput == ']' ||
     717     3507250 :                       *pszInput == ',' || *pszInput == '(' || *pszInput == ')'))
     718             :             {
     719             :                 break;
     720             :             }
     721     6091140 :             else if (!bInQuotedString &&
     722     3159470 :                      (*pszInput == ' ' || *pszInput == '\t' ||
     723     3158970 :                       *pszInput == 10 || *pszInput == 13))
     724             :             {
     725             :                 // Skip over whitespace.
     726             :             }
     727             :             else
     728             :             {
     729     6090600 :                 szToken[nTokenLen++] = *pszInput;
     730             :             }
     731             : 
     732     6827460 :             pszInput++;
     733             :         }
     734             : 
     735      832958 :         if (*pszInput == '\0' || nTokenLen == sizeof(szToken) - 1)
     736           0 :             return OGRERR_CORRUPT_DATA;
     737             : 
     738      832958 :         szToken[nTokenLen++] = '\0';
     739      832958 :         SetValue(szToken);
     740             :     }
     741             : 
     742             :     /* -------------------------------------------------------------------- */
     743             :     /*      Read children, if we have a sublist.                            */
     744             :     /* -------------------------------------------------------------------- */
     745      832958 :     if (*pszInput == '[' || *pszInput == '(')
     746             :     {
     747      518351 :         do
     748             :         {
     749      811670 :             pszInput++;  // Skip bracket or comma.
     750             : 
     751      811670 :             OGR_SRSNode *poNewChild = new OGR_SRSNode();
     752      811670 :             poNewChild->m_listener = m_listener;
     753             : 
     754      811670 :             (*pnNodes)++;
     755             :             const OGRErr eErr =
     756      811670 :                 poNewChild->importFromWkt(&pszInput, nRecLevel + 1, pnNodes);
     757      811670 :             if (eErr != OGRERR_NONE)
     758             :             {
     759           0 :                 delete poNewChild;
     760           0 :                 return eErr;
     761             :             }
     762             : 
     763      811670 :             AddChild(poNewChild);
     764             : 
     765             :             // Swallow whitespace.
     766      811670 :             while (isspace(static_cast<unsigned char>(*pszInput)))
     767           0 :                 pszInput++;
     768      811670 :         } while (*pszInput == ',');
     769             : 
     770      293319 :         if (*pszInput != ')' && *pszInput != ']')
     771           0 :             return OGRERR_CORRUPT_DATA;
     772             : 
     773      293319 :         pszInput++;
     774             :     }
     775             : 
     776      832958 :     *ppszInput = pszInput;
     777             : 
     778      832958 :     return OGRERR_NONE;
     779             : }
     780             : 
     781             : /************************************************************************/
     782             : /*                           MakeValueSafe()                            */
     783             : /************************************************************************/
     784             : 
     785             : /**
     786             :  * Massage value string, stripping special characters so it will be a
     787             :  * database safe string.
     788             :  *
     789             :  * The operation is also applies to all subnodes of the current node.
     790             :  */
     791             : 
     792           0 : void OGR_SRSNode::MakeValueSafe()
     793             : 
     794             : {
     795             :     /* -------------------------------------------------------------------- */
     796             :     /*      First process subnodes.                                         */
     797             :     /* -------------------------------------------------------------------- */
     798           0 :     for (int iChild = 0; iChild < GetChildCount(); iChild++)
     799             :     {
     800           0 :         GetChild(iChild)->MakeValueSafe();
     801             :     }
     802             : 
     803             :     /* -------------------------------------------------------------------- */
     804             :     /*      Skip numeric nodes.                                             */
     805             :     /* -------------------------------------------------------------------- */
     806           0 :     if ((pszValue[0] >= '0' && pszValue[0] <= '9') || pszValue[0] != '.')
     807           0 :         return;
     808             : 
     809             :     /* -------------------------------------------------------------------- */
     810             :     /*      Translate non-alphanumeric values to underscores.               */
     811             :     /* -------------------------------------------------------------------- */
     812           0 :     for (int i = 0; pszValue[i] != '\0'; i++)
     813             :     {
     814           0 :         if (!(pszValue[i] >= 'A' && pszValue[i] <= 'Z') &&
     815           0 :             !(pszValue[i] >= 'a' && pszValue[i] <= 'z') &&
     816           0 :             !(pszValue[i] >= '0' && pszValue[i] <= '9'))
     817             :         {
     818           0 :             pszValue[i] = '_';
     819             :         }
     820             :     }
     821             : 
     822             :     /* -------------------------------------------------------------------- */
     823             :     /*      Remove repeated and trailing underscores.                       */
     824             :     /* -------------------------------------------------------------------- */
     825           0 :     int j = 0;
     826           0 :     for (int i = 1; pszValue[i] != '\0'; i++)
     827             :     {
     828           0 :         if (pszValue[j] == '_' && pszValue[i] == '_')
     829           0 :             continue;
     830             : 
     831           0 :         pszValue[++j] = pszValue[i];
     832             :     }
     833             : 
     834           0 :     if (pszValue[j] == '_')
     835           0 :         pszValue[j] = '\0';
     836             :     else
     837           0 :         pszValue[j + 1] = '\0';
     838             : }
     839             : 
     840             : /************************************************************************/
     841             : /*                             StripNodes()                             */
     842             : /************************************************************************/
     843             : 
     844             : /**
     845             :  * Strip child nodes matching name.
     846             :  *
     847             :  * Removes any descendant nodes of this node that match the given name.
     848             :  * Of course children of removed nodes are also discarded.
     849             :  *
     850             :  * @param pszName the name for nodes that should be removed.
     851             :  */
     852             : 
     853        5390 : void OGR_SRSNode::StripNodes(const char *pszName)
     854             : 
     855             : {
     856             :     /* -------------------------------------------------------------------- */
     857             :     /*      Strip any children matching this name.                          */
     858             :     /* -------------------------------------------------------------------- */
     859        5390 :     while (FindChild(pszName) >= 0)
     860          70 :         DestroyChild(FindChild(pszName));
     861             : 
     862             :     /* -------------------------------------------------------------------- */
     863             :     /*      Recurse                                                         */
     864             :     /* -------------------------------------------------------------------- */
     865       10337 :     for (int i = 0; i < GetChildCount(); i++)
     866        5017 :         GetChild(i)->StripNodes(pszName);
     867        5320 : }

Generated by: LCOV version 1.14