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

Generated by: LCOV version 1.14