LCOV - code coverage report
Current view: directory - ogr - ogr_srsnode.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 248 220 88.7 %
Date: 2012-12-26 Functions: 23 20 87.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogr_srsnode.cpp 25340 2012-12-21 20:30:21Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  The OGR_SRSNode class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999,  Les Technologies SoftMap Inc.
      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 "ogr_spatialref.h"
      31                 : #include "ogr_p.h"
      32                 : 
      33                 : CPL_CVSID("$Id: ogr_srsnode.cpp 25340 2012-12-21 20:30:21Z rouault $");
      34                 : 
      35                 : /************************************************************************/
      36                 : /*                            OGR_SRSNode()                             */
      37                 : /************************************************************************/
      38                 : 
      39                 : /**
      40                 :  * Constructor.
      41                 :  *
      42                 :  * @param pszValueIn this optional parameter can be used to initialize
      43                 :  * the value of the node upon creation.  If omitted the node will be created
      44                 :  * with a value of "".  Newly created OGR_SRSNodes have no children.
      45                 :  */
      46                 : 
      47         3974986 : OGR_SRSNode::OGR_SRSNode( const char * pszValueIn )
      48                 : 
      49                 : {
      50         3974986 :     pszValue = CPLStrdup( pszValueIn );
      51                 : 
      52         3974986 :     nChildren = 0;
      53         3974986 :     papoChildNodes = NULL;
      54                 : 
      55         3974986 :     poParent = NULL;
      56         3974986 : }
      57                 : 
      58                 : /************************************************************************/
      59                 : /*                            ~OGR_SRSNode()                            */
      60                 : /************************************************************************/
      61                 : 
      62         3974986 : OGR_SRSNode::~OGR_SRSNode()
      63                 : 
      64                 : {
      65         3974986 :     CPLFree( pszValue );
      66                 : 
      67         3974986 :     ClearChildren();
      68         3974986 : }
      69                 : 
      70                 : /************************************************************************/
      71                 : /*                           ClearChildren()                            */
      72                 : /************************************************************************/
      73                 : 
      74         4765831 : void OGR_SRSNode::ClearChildren()
      75                 : 
      76                 : {
      77         8405705 :     for( int i = 0; i < nChildren; i++ )
      78                 :     {
      79         3639874 :         delete papoChildNodes[i];
      80                 :     }
      81                 : 
      82         4765831 :     CPLFree( papoChildNodes );
      83                 : 
      84         4765831 :     papoChildNodes = NULL;
      85         4765831 :     nChildren = 0;
      86         4765831 : }
      87                 : 
      88                 : /************************************************************************/
      89                 : /*                           GetChildCount()                            */
      90                 : /************************************************************************/
      91                 : 
      92                 : /**
      93                 :  * \fn int OGR_SRSNode::GetChildCount() const;
      94                 :  *
      95                 :  * Get number of children nodes.
      96                 :  *
      97                 :  * @return 0 for leaf nodes, or the number of children nodes. 
      98                 :  */
      99                 : 
     100                 : /************************************************************************/
     101                 : /*                              GetChild()                              */
     102                 : /************************************************************************/
     103                 : 
     104                 : /**
     105                 :  * Fetch requested child.
     106                 :  *
     107                 :  * @param iChild the index of the child to fetch, from 0 to
     108                 :  * GetChildCount() - 1.
     109                 :  *
     110                 :  * @return a pointer to the child OGR_SRSNode, or NULL if there is no such
     111                 :  * child. 
     112                 :  */
     113                 : 
     114        16343801 : OGR_SRSNode *OGR_SRSNode::GetChild( int iChild )
     115                 : 
     116                 : {
     117        16343801 :     if( iChild < 0 || iChild >= nChildren )
     118               0 :         return NULL;
     119                 :     else
     120        16343801 :         return papoChildNodes[iChild];
     121                 : }
     122                 : 
     123         4415573 : const OGR_SRSNode *OGR_SRSNode::GetChild( int iChild ) const
     124                 : 
     125                 : {
     126         4415573 :     if( iChild < 0 || iChild >= nChildren )
     127               0 :         return NULL;
     128                 :     else
     129         4415573 :         return papoChildNodes[iChild];
     130                 : }
     131                 : 
     132                 : /************************************************************************/
     133                 : /*                              GetNode()                               */
     134                 : /************************************************************************/
     135                 : 
     136                 : /**
     137                 :  * Find named node in tree.
     138                 :  *
     139                 :  * This method does a pre-order traversal of the node tree searching for
     140                 :  * a node with this exact value (case insensitive), and returns it.  Leaf
     141                 :  * nodes are not considered, under the assumption that they are just
     142                 :  * attribute value nodes.
     143                 :  *
     144                 :  * If a node appears more than once in the tree (such as UNIT for instance),
     145                 :  * the first encountered will be returned.  Use GetNode() on a subtree to be
     146                 :  * more specific. 
     147                 :  *
     148                 :  * @param pszName the name of the node to search for.
     149                 :  *
     150                 :  * @return a pointer to the node found, or NULL if none.
     151                 :  */
     152                 : 
     153         4773759 : OGR_SRSNode *OGR_SRSNode::GetNode( const char * pszName )
     154                 : 
     155                 : {
     156                 :     int  i;
     157                 : 
     158         4773759 :     if( this == NULL )
     159               0 :         return NULL;
     160                 :     
     161         4773759 :     if( nChildren > 0 && EQUAL(pszName,pszValue) )
     162          659536 :         return this;
     163                 : 
     164                 : /* -------------------------------------------------------------------- */
     165                 : /*      First we check the immediate children so we will get an         */
     166                 : /*      immediate child in preference to a subchild.                    */
     167                 : /* -------------------------------------------------------------------- */
     168        10563851 :     for( i = 0; i < nChildren; i++ )
     169                 :     {
     170         8250864 :         if( EQUAL(papoChildNodes[i]->pszValue,pszName) 
     171          900618 :             && papoChildNodes[i]->nChildren > 0 )
     172          900618 :             return papoChildNodes[i];
     173                 :     }
     174                 : 
     175                 : /* -------------------------------------------------------------------- */
     176                 : /*      Then get each child to check their children.                    */
     177                 : /* -------------------------------------------------------------------- */
     178         5872805 :     for( i = 0; i < nChildren; i++ )
     179                 :     {
     180                 :         OGR_SRSNode *poNode;
     181                 : 
     182         3105465 :         poNode = papoChildNodes[i]->GetNode( pszName );
     183         3105465 :         if( poNode != NULL )
     184          446265 :             return poNode;
     185                 :     }
     186                 : 
     187         2767340 :     return NULL;
     188                 : }
     189                 : 
     190            1461 : const OGR_SRSNode *OGR_SRSNode::GetNode( const char * pszName ) const
     191                 : 
     192                 : {
     193            1461 :     return ((OGR_SRSNode *) this)->GetNode( pszName );
     194                 : }
     195                 : 
     196                 : /************************************************************************/
     197                 : /*                              AddChild()                              */
     198                 : /************************************************************************/
     199                 : 
     200                 : /**
     201                 :  * Add passed node as a child of target node.
     202                 :  *
     203                 :  * Note that ownership of the passed node is assumed by the node on which
     204                 :  * the method is invoked ... use the Clone() method if the original is to
     205                 :  * be preserved.  New children are always added at the end of the list.
     206                 :  *
     207                 :  * @param poNew the node to add as a child.
     208                 :  */
     209                 : 
     210         3866888 : void OGR_SRSNode::AddChild( OGR_SRSNode * poNew )
     211                 : 
     212                 : {
     213         3866888 :     InsertChild( poNew, nChildren );
     214         3866888 : }
     215                 : 
     216                 : /************************************************************************/
     217                 : /*                            InsertChild()                             */
     218                 : /************************************************************************/
     219                 : 
     220                 : /**
     221                 :  * Insert the passed node as a child of target node, at the indicated
     222                 :  * position. 
     223                 :  *
     224                 :  * Note that ownership of the passed node is assumed by the node on which
     225                 :  * the method is invoked ... use the Clone() method if the original is to
     226                 :  * be preserved.  All existing children at location iChild and beyond are
     227                 :  * push down one space to make space for the new child. 
     228                 :  *
     229                 :  * @param poNew the node to add as a child.
     230                 :  * @param iChild position to insert, use 0 to insert at the beginning. 
     231                 :  */
     232                 : 
     233         3887510 : void OGR_SRSNode::InsertChild( OGR_SRSNode * poNew, int iChild )
     234                 : 
     235                 : {
     236         3887510 :     if( iChild > nChildren )
     237               0 :         iChild = nChildren;
     238                 : 
     239         3887510 :     nChildren++;
     240                 :     papoChildNodes = (OGR_SRSNode **)
     241         3887510 :         CPLRealloc( papoChildNodes, sizeof(void*) * nChildren );
     242                 : 
     243                 :     memmove( papoChildNodes + iChild + 1, papoChildNodes + iChild,
     244         3887510 :              sizeof(void*) * (nChildren - iChild - 1) );
     245                 :     
     246         3887510 :     papoChildNodes[iChild] = poNew;
     247         3887510 :     poNew->poParent = this;
     248         3887510 : }
     249                 : 
     250                 : /************************************************************************/
     251                 : /*                            DestroyChild()                            */
     252                 : /************************************************************************/
     253                 : 
     254                 : /**
     255                 :  * Remove a child node, and it's subtree.
     256                 :  *
     257                 :  * Note that removing a child node will result in children after it
     258                 :  * being renumbered down one.
     259                 :  *
     260                 :  * @param iChild the index of the child.
     261                 :  */
     262                 : 
     263          247659 : void OGR_SRSNode::DestroyChild( int iChild )
     264                 : 
     265                 : {
     266          247659 :     if( iChild < 0 || iChild >= nChildren )
     267              23 :         return;
     268                 : 
     269          247636 :     delete papoChildNodes[iChild];
     270          586163 :     while( iChild < nChildren-1 )
     271                 :     {
     272           90891 :         papoChildNodes[iChild] = papoChildNodes[iChild+1];
     273           90891 :         iChild++;
     274                 :     }
     275                 : 
     276          247636 :     nChildren--;
     277                 : }
     278                 : 
     279                 : /************************************************************************/
     280                 : /*                             FindChild()                              */
     281                 : /************************************************************************/
     282                 : 
     283                 : /**
     284                 :  * Find the index of the child matching the given string.
     285                 :  *
     286                 :  * Note that the node value must match pszValue with the exception of
     287                 :  * case.  The comparison is case insensitive.
     288                 :  *
     289                 :  * @param pszValue the node value being searched for.
     290                 :  *
     291                 :  * @return the child index, or -1 on failure. 
     292                 :  */
     293                 : 
     294         6449527 : int OGR_SRSNode::FindChild( const char * pszValue ) const
     295                 : 
     296                 : {
     297        15465380 :     for( int i = 0; i < nChildren; i++ )
     298                 :     {
     299         9608680 :         if( EQUAL(papoChildNodes[i]->pszValue,pszValue) )
     300          592827 :             return i;
     301                 :     }
     302                 : 
     303         5856700 :     return -1;
     304                 : }
     305                 : 
     306                 : /************************************************************************/
     307                 : /*                              GetValue()                              */
     308                 : /************************************************************************/
     309                 : 
     310                 : /**
     311                 :  * \fn const char *OGR_SRSNode::GetValue() const;
     312                 :  *
     313                 :  * Fetch value string for this node.
     314                 :  *
     315                 :  * @return A non-NULL string is always returned.  The returned pointer is to
     316                 :  * the internal value of this node, and should not be modified, or freed.
     317                 :  */
     318                 : 
     319                 : /************************************************************************/
     320                 : /*                              SetValue()                              */
     321                 : /************************************************************************/
     322                 : 
     323                 : /**
     324                 :  * Set the node value.
     325                 :  *
     326                 :  * @param pszNewValue the new value to assign to this node.  The passed
     327                 :  * string is duplicated and remains the responsibility of the caller.
     328                 :  */
     329                 : 
     330          950003 : void OGR_SRSNode::SetValue( const char * pszNewValue )
     331                 : 
     332                 : {
     333          950003 :     CPLFree( pszValue );
     334          950003 :     pszValue = CPLStrdup( pszNewValue );
     335          950003 : }
     336                 : 
     337                 : /************************************************************************/
     338                 : /*                               Clone()                                */
     339                 : /************************************************************************/
     340                 : 
     341                 : /**
     342                 :  * Make a duplicate of this node, and it's children.
     343                 :  *
     344                 :  * @return a new node tree, which becomes the responsiblity of the caller.
     345                 :  */
     346                 : 
     347         1621595 : OGR_SRSNode *OGR_SRSNode::Clone() const
     348                 : 
     349                 : {
     350                 :     OGR_SRSNode *poNew;
     351                 : 
     352         1621595 :     poNew = new OGR_SRSNode( pszValue );
     353                 : 
     354         3201749 :     for( int i = 0; i < nChildren; i++ )
     355                 :     {
     356         1580154 :         poNew->AddChild( papoChildNodes[i]->Clone() );
     357                 :     }
     358                 : 
     359         1621595 :     return poNew;
     360                 : }
     361                 : 
     362                 : /************************************************************************/
     363                 : /*                            NeedsQuoting()                            */
     364                 : /*                                                                      */
     365                 : /*      Does this node need to be quoted when it is exported to Wkt?    */
     366                 : /************************************************************************/
     367                 : 
     368         3187439 : int OGR_SRSNode::NeedsQuoting() const
     369                 : 
     370                 : {
     371                 :     // non-terminals are never quoted.
     372         3187439 :     if( GetChildCount() != 0 )
     373         1103098 :         return FALSE;
     374                 : 
     375                 :     // As per bugzilla bug 201, the OGC spec says the authority code
     376                 :     // needs to be quoted even though it appears well behaved.
     377         2084341 :     if( poParent != NULL && EQUAL(poParent->GetValue(),"AUTHORITY") )
     378          275690 :         return TRUE;
     379                 :     
     380                 :     // As per bugzilla bug 294, the OGC spec says the direction
     381                 :     // values for the AXIS keywords should *not* be quoted.
     382         1808651 :     if( poParent != NULL && EQUAL(poParent->GetValue(),"AXIS") 
     383                 :         && this != poParent->GetChild(0) )
     384           31193 :         return FALSE;
     385                 : 
     386                 :     // Strings starting with e or E are not valid numeric values, so they
     387                 :     // need quoting, like in AXIS["E",EAST] 
     388         1777458 :     if( (pszValue[0] == 'e' || pszValue[0] == 'E') )
     389           14754 :         return TRUE;
     390                 : 
     391                 :     // Non-numeric tokens are generally quoted while clean numeric values
     392                 :     // are generally not. 
     393         7214587 :     for( int i = 0; pszValue[i] != '\0'; i++ )
     394                 :     {
     395        11575110 :         if( (pszValue[i] < '0' || pszValue[i] > '9')
     396         1391986 :             && pszValue[i] != '.'
     397         1930371 :             && pszValue[i] != '-' && pszValue[i] != '+'
     398         1867264 :             && pszValue[i] != 'e' && pszValue[i] != 'E' )
     399          933606 :             return TRUE;
     400                 :     }
     401                 : 
     402          829098 :     return FALSE;
     403                 : }
     404                 : 
     405                 : /************************************************************************/
     406                 : /*                            exportToWkt()                             */
     407                 : /************************************************************************/
     408                 : 
     409                 : /**
     410                 :  * Convert this tree of nodes into WKT format.
     411                 :  *
     412                 :  * Note that the returned WKT string should be freed with OGRFree() or
     413                 :  * CPLFree() when no longer needed.  It is the responsibility of the caller.
     414                 :  *
     415                 :  * @param ppszResult the resulting string is returned in this pointer.
     416                 :  *
     417                 :  * @return currently OGRERR_NONE is always returned, but the future it
     418                 :  * is possible error conditions will develop. 
     419                 :  */
     420                 :  
     421                 : 
     422         3184388 : OGRErr OGR_SRSNode::exportToWkt( char ** ppszResult ) const
     423                 : 
     424                 : {
     425         3184388 :     char        **papszChildrenWkt = NULL;
     426         3184388 :     int         nLength = strlen(pszValue)+4;
     427                 :     int         i;
     428                 : 
     429                 : /* -------------------------------------------------------------------- */
     430                 : /*      Build a list of the WKT format for the children.                */
     431                 : /* -------------------------------------------------------------------- */
     432         3184388 :     papszChildrenWkt = (char **) CPLCalloc(sizeof(char*),(nChildren+1));
     433                 :     
     434         6291496 :     for( i = 0; i < nChildren; i++ )
     435                 :     {
     436         3107108 :         papoChildNodes[i]->exportToWkt( papszChildrenWkt + i );
     437         3107108 :         nLength += strlen(papszChildrenWkt[i]) + 1;
     438                 :     }
     439                 : 
     440                 : /* -------------------------------------------------------------------- */
     441                 : /*      Allocate the result string.                                     */
     442                 : /* -------------------------------------------------------------------- */
     443         3184388 :     *ppszResult = (char *) CPLMalloc(nLength);
     444         3184388 :     *ppszResult[0] = '\0';
     445                 :     
     446                 : /* -------------------------------------------------------------------- */
     447                 : /*      Capture this nodes value.  We put it in double quotes if        */
     448                 : /*      this is a leaf node, otherwise we assume it is a well formed    */
     449                 : /*      node name.                                                      */
     450                 : /* -------------------------------------------------------------------- */
     451         3184388 :     if( NeedsQuoting() )
     452                 :     {
     453         1222790 :         strcat( *ppszResult, "\"" );
     454         1222790 :         strcat( *ppszResult, pszValue ); /* should we do quoting? */
     455         1222790 :         strcat( *ppszResult, "\"" );
     456                 :     }
     457                 :     else
     458         1961598 :         strcat( *ppszResult, pszValue );
     459                 : 
     460                 : /* -------------------------------------------------------------------- */
     461                 : /*      Add the children strings with appropriate brackets and commas.  */
     462                 : /* -------------------------------------------------------------------- */
     463         3184388 :     if( nChildren > 0 )
     464         1102059 :         strcat( *ppszResult, "[" );
     465                 :     
     466         6291496 :     for( i = 0; i < nChildren; i++ )
     467                 :     {
     468         3107108 :         strcat( *ppszResult, papszChildrenWkt[i] );
     469         3107108 :         if( i == nChildren-1 )
     470         1102059 :             strcat( *ppszResult, "]" );
     471                 :         else
     472         2005049 :             strcat( *ppszResult, "," );
     473                 :     }
     474                 : 
     475         3184388 :     CSLDestroy( papszChildrenWkt );
     476                 : 
     477         3184388 :     return OGRERR_NONE;
     478                 : }
     479                 : 
     480                 : /************************************************************************/
     481                 : /*                         exportToPrettyWkt()                          */
     482                 : /************************************************************************/
     483                 : 
     484            3051 : OGRErr OGR_SRSNode::exportToPrettyWkt( char ** ppszResult, int nDepth ) const
     485                 : 
     486                 : {
     487            3051 :     char        **papszChildrenWkt = NULL;
     488            3051 :     int         nLength = strlen(pszValue)+4;
     489                 :     int         i;
     490                 : 
     491                 : /* -------------------------------------------------------------------- */
     492                 : /*      Build a list of the WKT format for the children.                */
     493                 : /* -------------------------------------------------------------------- */
     494            3051 :     papszChildrenWkt = (char **) CPLCalloc(sizeof(char*),(nChildren+1));
     495                 :     
     496            6033 :     for( i = 0; i < nChildren; i++ )
     497                 :     {
     498            2982 :         papoChildNodes[i]->exportToPrettyWkt( papszChildrenWkt + i,
     499            5964 :                                               nDepth + 1);
     500            2982 :         nLength += strlen(papszChildrenWkt[i]) + 2 + nDepth*4;
     501                 :     }
     502                 : 
     503                 : /* -------------------------------------------------------------------- */
     504                 : /*      Allocate the result string.                                     */
     505                 : /* -------------------------------------------------------------------- */
     506            3051 :     *ppszResult = (char *) CPLMalloc(nLength);
     507            3051 :     *ppszResult[0] = '\0';
     508                 :     
     509                 : /* -------------------------------------------------------------------- */
     510                 : /*      Capture this nodes value.  We put it in double quotes if        */
     511                 : /*      this is a leaf node, otherwise we assume it is a well formed    */
     512                 : /*      node name.                                                      */
     513                 : /* -------------------------------------------------------------------- */
     514            3051 :     if( NeedsQuoting() )
     515                 :     {
     516            1260 :         strcat( *ppszResult, "\"" );
     517            1260 :         strcat( *ppszResult, pszValue ); /* should we do quoting? */
     518            1260 :         strcat( *ppszResult, "\"" );
     519                 :     }
     520                 :     else
     521            1791 :         strcat( *ppszResult, pszValue );
     522                 : 
     523                 : /* -------------------------------------------------------------------- */
     524                 : /*      Add the children strings with appropriate brackets and commas.  */
     525                 : /* -------------------------------------------------------------------- */
     526            3051 :     if( nChildren > 0 )
     527            1039 :         strcat( *ppszResult, "[" );
     528                 :     
     529            6033 :     for( i = 0; i < nChildren; i++ )
     530                 :     {
     531            2982 :         if( papoChildNodes[i]->GetChildCount() > 0 )
     532                 :         {
     533                 :             int  j;
     534                 : 
     535             970 :             strcat( *ppszResult, "\n" );
     536            7870 :             for( j = 0; j < 4*nDepth; j++ )
     537            6900 :                 strcat( *ppszResult, " " );
     538                 :         }
     539            2982 :         strcat( *ppszResult, papszChildrenWkt[i] );
     540            2982 :         if( i < nChildren-1 )
     541            1943 :             strcat( *ppszResult, "," );
     542                 :     }
     543                 : 
     544            3051 :     if( nChildren > 0 )
     545                 :     {
     546            1039 :         if( (*ppszResult)[strlen(*ppszResult)-1] == ',' )
     547               0 :             (*ppszResult)[strlen(*ppszResult)-1] = '\0';
     548                 :         
     549            1039 :         strcat( *ppszResult, "]" );
     550                 :     }
     551                 : 
     552            3051 :     CSLDestroy( papszChildrenWkt );
     553                 : 
     554            3051 :     return OGRERR_NONE;
     555                 : }
     556                 : 
     557                 : /************************************************************************/
     558                 : /*                           importFromWkt()                            */
     559                 : /************************************************************************/
     560                 : 
     561                 : /**
     562                 :  * Import from WKT string.
     563                 :  *
     564                 :  * This method will wipe the existing children and value of this node, and
     565                 :  * reassign them based on the contents of the passed WKT string.  Only as
     566                 :  * much of the input string as needed to construct this node, and it's
     567                 :  * children is consumed from the input string, and the input string pointer
     568                 :  * is then updated to point to the remaining (unused) input.
     569                 :  *
     570                 :  * @param ppszInput Pointer to pointer to input.  The pointer is updated to
     571                 :  * point to remaining unused input text.
     572                 :  *
     573                 :  * @return OGRERR_NONE if import succeeds, or OGRERR_CORRUPT_DATA if it
     574                 :  * fails for any reason.
     575                 :  */
     576                 : 
     577          790845 : OGRErr OGR_SRSNode::importFromWkt( char ** ppszInput )
     578                 : 
     579                 : {
     580          790845 :     const char  *pszInput = *ppszInput;
     581          790845 :     int         bInQuotedString = FALSE;
     582                 :     
     583                 : /* -------------------------------------------------------------------- */
     584                 : /*      Clear any existing children of this node.                       */
     585                 : /* -------------------------------------------------------------------- */
     586          790845 :     ClearChildren();
     587                 :     
     588                 : /* -------------------------------------------------------------------- */
     589                 : /*      Read the ``value'' for this node.                               */
     590                 : /* -------------------------------------------------------------------- */
     591                 :     char        szToken[512];
     592          790845 :     int         nTokenLen = 0;
     593                 :     
     594         9611984 :     while( *pszInput != '\0' && nTokenLen < (int) sizeof(szToken)-1 )
     595                 :     {
     596         8821117 :         if( *pszInput == '"' )
     597                 :         {
     598          603066 :             bInQuotedString = !bInQuotedString;
     599                 :         }
     600         8218051 :         else if( !bInQuotedString
     601                 :               && (*pszInput == '[' || *pszInput == ']' || *pszInput == ','
     602                 :                   || *pszInput == '(' || *pszInput == ')' ) )
     603                 :         {
     604          790823 :             break;
     605                 :         }
     606         7427228 :         else if( !bInQuotedString 
     607                 :                  && (*pszInput == ' ' || *pszInput == '\t' 
     608                 :                      || *pszInput == 10 || *pszInput == 13) )
     609                 :         {
     610                 :             /* just skip over whitespace */
     611                 :         } 
     612                 :         else
     613                 :         {
     614         7412406 :             szToken[nTokenLen++] = *pszInput;
     615                 :         }
     616                 : 
     617         8030294 :         pszInput++;
     618                 :     }
     619                 : 
     620          790845 :     if( *pszInput == '\0' || nTokenLen == sizeof(szToken) - 1 )
     621              22 :         return OGRERR_CORRUPT_DATA;
     622                 : 
     623          790823 :     szToken[nTokenLen++] = '\0';
     624          790823 :     SetValue( szToken );
     625                 : 
     626                 : /* -------------------------------------------------------------------- */
     627                 : /*      Read children, if we have a sublist.                            */
     628                 : /* -------------------------------------------------------------------- */
     629          790823 :     if( *pszInput == '[' || *pszInput == '(' )
     630                 :     {
     631          766098 :         do
     632                 :         {
     633                 :             OGR_SRSNode *poNewChild;
     634                 :             OGRErr      eErr;
     635                 : 
     636          766098 :             pszInput++; // Skip bracket or comma.
     637                 : 
     638          766098 :             poNewChild = new OGR_SRSNode();
     639                 : 
     640          766098 :             eErr = poNewChild->importFromWkt( (char **) &pszInput );
     641          766098 :             if( eErr != OGRERR_NONE )
     642                 :             {
     643               0 :                 delete poNewChild;
     644               0 :                 return eErr;
     645                 :             }
     646                 : 
     647          766098 :             AddChild( poNewChild );
     648                 :             
     649                 :             // swallow whitespace
     650         1532196 :             while( isspace(*pszInput) ) 
     651               0 :                 pszInput++;
     652                 : 
     653                 :         } while( *pszInput == ',' );
     654                 : 
     655          278800 :         if( *pszInput != ')' && *pszInput != ']' )
     656               0 :             return OGRERR_CORRUPT_DATA;
     657                 : 
     658          278800 :         pszInput++;
     659                 :     }
     660                 : 
     661          790823 :     *ppszInput = (char *) pszInput;
     662                 : 
     663          790823 :     return OGRERR_NONE;
     664                 : }
     665                 : 
     666                 : /************************************************************************/
     667                 : /*                           MakeValueSafe()                            */
     668                 : /************************************************************************/
     669                 : 
     670                 : /**
     671                 :  * Massage value string, stripping special characters so it will be a
     672                 :  * database safe string.
     673                 :  *
     674                 :  * The operation is also applies to all subnodes of the current node.
     675                 :  */
     676                 : 
     677                 : 
     678               0 : void OGR_SRSNode::MakeValueSafe()
     679                 : 
     680                 : {
     681                 :     int         i, j;
     682                 : 
     683                 : /* -------------------------------------------------------------------- */
     684                 : /*      First process subnodes.                                         */
     685                 : /* -------------------------------------------------------------------- */
     686               0 :     for( int iChild = 0; iChild < GetChildCount(); iChild++ )
     687                 :     {
     688               0 :         GetChild(iChild)->MakeValueSafe();
     689                 :     }
     690                 : 
     691                 : /* -------------------------------------------------------------------- */
     692                 : /*      Skip numeric nodes.                                             */
     693                 : /* -------------------------------------------------------------------- */
     694               0 :     if( (pszValue[0] >= '0' && pszValue[0] <= '9') || pszValue[0] != '.' )
     695               0 :         return;
     696                 :     
     697                 : /* -------------------------------------------------------------------- */
     698                 : /*      Translate non-alphanumeric values to underscores.               */
     699                 : /* -------------------------------------------------------------------- */
     700               0 :     for( i = 0; pszValue[i] != '\0'; i++ )
     701                 :     {
     702               0 :         if( !(pszValue[i] >= 'A' && pszValue[i] <= 'Z')
     703               0 :             && !(pszValue[i] >= 'a' && pszValue[i] <= 'z')
     704               0 :             && !(pszValue[i] >= '0' && pszValue[i] <= '9') )
     705                 :         {
     706               0 :             pszValue[i] = '_';
     707                 :         }
     708                 :     }
     709                 : 
     710                 : /* -------------------------------------------------------------------- */
     711                 : /*      Remove repeated and trailing underscores.                       */
     712                 : /* -------------------------------------------------------------------- */
     713               0 :     for( i = 1, j = 0; pszValue[i] != '\0'; i++ )
     714                 :     {
     715               0 :         if( pszValue[j] == '_' && pszValue[i] == '_' )
     716               0 :             continue;
     717                 : 
     718               0 :         pszValue[++j] = pszValue[i];
     719                 :     }
     720                 :     
     721               0 :     if( pszValue[j] == '_' )
     722               0 :         pszValue[j] = '\0';
     723                 :     else
     724               0 :         pszValue[j+1] = '\0';
     725                 : }
     726                 : 
     727                 : /************************************************************************/
     728                 : /*                           applyRemapper()                            */
     729                 : /************************************************************************/
     730                 : 
     731                 : /**
     732                 :  * Remap node values matching list.
     733                 :  *
     734                 :  * Remap the value of this node or any of it's children if it matches
     735                 :  * one of the values in the source list to the corresponding value from
     736                 :  * the destination list.  If the pszNode value is set, only do so if the
     737                 :  * parent node matches that value.  Even if a replacement occurs, searching
     738                 :  * continues.
     739                 :  *
     740                 :  * @param pszNode Restrict remapping to children of this type of node 
     741                 :  *                (eg. "PROJECTION")
     742                 :  * @param papszSrcValues a NULL terminated array of source string.  If the
     743                 :  * node value matches one of these (case insensitive) then replacement occurs.
     744                 :  * @param papszDstValues an array of destination strings.  On a match, the
     745                 :  * one corresponding to a source value will be used to replace a node.
     746                 :  * @param nStepSize increment when stepping through source and destination
     747                 :  * arrays, allowing source and destination arrays to be one interleaved array
     748                 :  * for instances.  Defaults to 1.
     749                 :  * @param bChildOfHit Only TRUE if we the current node is the child of a match,
     750                 :  * and so needs to be set.  Application code would normally pass FALSE for this
     751                 :  * argument.
     752                 :  * 
     753                 :  * @return returns OGRERR_NONE unless something bad happens.  There is no
     754                 :  * indication returned about whether any replacement occured.  
     755                 :  */
     756                 : 
     757         6313187 : OGRErr OGR_SRSNode::applyRemapper( const char *pszNode, 
     758                 :                                    char **papszSrcValues, 
     759                 :                                    char **papszDstValues, 
     760                 :                                    int nStepSize, int bChildOfHit )
     761                 : 
     762                 : {
     763                 :     int i;
     764                 : 
     765                 : /* -------------------------------------------------------------------- */
     766                 : /*      Scan for value, and replace if our parent was a "hit".          */
     767                 : /* -------------------------------------------------------------------- */
     768         6313187 :     if( bChildOfHit || pszNode == NULL )
     769                 :     {
     770        52349456 :         for( i = 0; papszSrcValues[i] != NULL; i += nStepSize )
     771                 :         {
     772        51971701 :             if( EQUAL(papszSrcValues[i],pszValue) && 
     773           80501 :                 ! EQUAL(papszDstValues[i],"") )
     774                 :             {
     775           79076 :                 SetValue( papszDstValues[i] );
     776           79076 :                 break;
     777                 :             }
     778                 :         }
     779                 :     }
     780                 : 
     781                 : /* -------------------------------------------------------------------- */
     782                 : /*      Are the the target node?                                        */
     783                 : /* -------------------------------------------------------------------- */
     784         6313187 :     if( pszNode != NULL )
     785         6313187 :         bChildOfHit = EQUAL(pszValue,pszNode);
     786                 : 
     787                 : /* -------------------------------------------------------------------- */
     788                 : /*      Recurse                                                         */
     789                 : /* -------------------------------------------------------------------- */
     790        12432480 :     for( i = 0; i < GetChildCount(); i++ )
     791                 :     {
     792                 :         GetChild(i)->applyRemapper( pszNode, papszSrcValues, 
     793         6119293 :                                     papszDstValues, nStepSize, bChildOfHit );
     794                 :     }
     795                 : 
     796         6313187 :     return OGRERR_NONE;
     797                 : }
     798                 :                                    
     799                 : /************************************************************************/
     800                 : /*                             StripNodes()                             */
     801                 : /************************************************************************/
     802                 : 
     803                 : /**
     804                 :  * Strip child nodes matching name.
     805                 :  *
     806                 :  * Removes any decendent nodes of this node that match the given name. 
     807                 :  * Of course children of removed nodes are also discarded.
     808                 :  *
     809                 :  * @param pszName the name for nodes that should be removed.
     810                 :  */
     811                 : 
     812         5630111 : void OGR_SRSNode::StripNodes( const char * pszName )
     813                 : 
     814                 : {
     815                 : /* -------------------------------------------------------------------- */
     816                 : /*      Strip any children matching this name.                          */
     817                 : /* -------------------------------------------------------------------- */
     818        11504278 :     while( FindChild( pszName ) >= 0 )
     819          244056 :         DestroyChild( FindChild( pszName ) );
     820                 : 
     821                 : /* -------------------------------------------------------------------- */
     822                 : /*      Recurse                                                         */
     823                 : /* -------------------------------------------------------------------- */
     824        11093007 :     for( int i = 0; i < GetChildCount(); i++ )
     825         5462896 :         GetChild(i)->StripNodes( pszName );
     826         5630111 : }
     827                 : 
     828                 : /************************************************************************/
     829                 : /*                           FixupOrdering()                            */
     830                 : /************************************************************************/
     831                 : 
     832                 : /* EXTENSION ... being a OSR extension... is arbitrary placed before the AUTHORITY */
     833                 : static const char * const apszPROJCSRule[] = 
     834                 : { "PROJCS", "GEOGCS", "PROJECTION", "PARAMETER", "UNIT", "AXIS", "EXTENSION", "AUTHORITY", 
     835                 :   NULL };
     836                 : 
     837                 : static const char * const apszDATUMRule[] = 
     838                 : { "DATUM", "SPHEROID", "TOWGS84", "AUTHORITY", NULL };
     839                 : 
     840                 : static const char * const apszGEOGCSRule[] = 
     841                 : { "GEOGCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "AUTHORITY", NULL };
     842                 : 
     843                 : static const char * const apszGEOCCSRule[] = 
     844                 : { "GEOCCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "AUTHORITY", NULL };
     845                 : 
     846                 : static const char * const *apszOrderingRules[] = {
     847                 :     apszPROJCSRule, apszGEOGCSRule, apszDATUMRule, apszGEOCCSRule, NULL };
     848                 : 
     849                 : /**
     850                 :  * Correct parameter ordering to match CT Specification.
     851                 :  *
     852                 :  * Some mechanisms to create WKT using OGRSpatialReference, and some
     853                 :  * imported WKT fail to maintain the order of parameters required according
     854                 :  * to the BNF definitions in the OpenGIS SF-SQL and CT Specifications.  This
     855                 :  * method attempts to massage things back into the required order.
     856                 :  *
     857                 :  * This method will reorder the children of the node it is invoked on and
     858                 :  * then recurse to all children to fix up their children.
     859                 :  *
     860                 :  * @return OGRERR_NONE on success or an error code if something goes 
     861                 :  * wrong.  
     862                 :  */
     863                 : 
     864         2315700 : OGRErr OGR_SRSNode::FixupOrdering()
     865                 : 
     866                 : {
     867                 :     int    i;
     868                 : 
     869                 : /* -------------------------------------------------------------------- */
     870                 : /*      Recurse ordering children.                                      */
     871                 : /* -------------------------------------------------------------------- */
     872         4592072 :     for( i = 0; i < GetChildCount(); i++ )
     873         2276372 :         GetChild(i)->FixupOrdering();
     874                 : 
     875         2315700 :     if( GetChildCount() < 3 )
     876         2061829 :         return OGRERR_NONE;
     877                 : 
     878                 : /* -------------------------------------------------------------------- */
     879                 : /*      Is this a node for which an ordering rule exists?               */
     880                 : /* -------------------------------------------------------------------- */
     881          253871 :     const char * const * papszRule = NULL;
     882                 : 
     883          969298 :     for( i = 0; apszOrderingRules[i] != NULL; i++ )
     884                 :     {
     885          816972 :         if( EQUAL(apszOrderingRules[i][0],pszValue) )
     886                 :         {
     887          101545 :             papszRule = apszOrderingRules[i] + 1;
     888          101545 :             break;
     889                 :         }
     890                 :     }
     891                 : 
     892          253871 :     if( papszRule == NULL )
     893          152326 :         return OGRERR_NONE;
     894                 : 
     895                 : /* -------------------------------------------------------------------- */
     896                 : /*      If we have a rule, apply it.  We create an array                */
     897                 : /*      (panChildPr) with the priority code for each child (derived     */
     898                 : /*      from the rule) and we then bubble sort based on this.           */
     899                 : /* -------------------------------------------------------------------- */
     900          101545 :     int  *panChildKey = (int *) CPLCalloc(sizeof(int),GetChildCount());
     901                 : 
     902          697777 :     for( i = 1; i < GetChildCount(); i++ )
     903                 :     {
     904          596232 :         panChildKey[i] = CSLFindString( (char**) papszRule, 
     905          596232 :                                         GetChild(i)->GetValue() );
     906          596232 :         if( panChildKey[i] == -1 )
     907                 :         {
     908                 :             CPLDebug( "OGRSpatialReference", 
     909                 :                       "Found unexpected key %s when trying to order SRS nodes.",
     910               0 :                       GetChild(i)->GetValue() );
     911                 :         }
     912                 :     }
     913                 : 
     914                 : /* -------------------------------------------------------------------- */
     915                 : /*      Sort - Note we don't try to do anything with the first child    */
     916                 : /*      which we assume is a name string.                               */
     917                 : /* -------------------------------------------------------------------- */
     918          101545 :     int j, bChange = TRUE;
     919                 : 
     920          242810 :     for( i = 1; bChange && i < GetChildCount()-1; i++ )
     921                 :     {
     922          141265 :         bChange = FALSE;
     923          879443 :         for( j = 1; j < GetChildCount()-i; j++ )
     924                 :         {
     925          738178 :             if( panChildKey[j] == -1 || panChildKey[j+1] == -1 )
     926               0 :                 continue;
     927                 : 
     928          738178 :             if( panChildKey[j] > panChildKey[j+1] )
     929                 :             {
     930          180591 :                 OGR_SRSNode *poTemp = papoChildNodes[j];
     931          180591 :                 int          nKeyTemp = panChildKey[j];
     932                 : 
     933          180591 :                 papoChildNodes[j] = papoChildNodes[j+1];
     934          180591 :                 papoChildNodes[j+1] = poTemp;
     935                 : 
     936          180591 :                 nKeyTemp = panChildKey[j];
     937          180591 :                 panChildKey[j] = panChildKey[j+1];
     938          180591 :                 panChildKey[j+1] = nKeyTemp;
     939                 : 
     940          180591 :                 bChange = TRUE;
     941                 :             }
     942                 :         }
     943                 :     }
     944                 : 
     945          101545 :     CPLFree( panChildKey );
     946                 : 
     947          101545 :     return OGRERR_NONE;
     948                 : }
     949                 : 
     950                 : 

Generated by: LCOV version 1.7